一、注意事项和重要代码
1、使用场景:qt,需要对服务器发送请求(包含报文),并接收服务器的返回值;服务器用的是mongoose模拟的服务器;
2、发送请求的方式有两种:GET和POST,两种方式的不同:Get将参数直接与网址整合为一个整体,而Post则将其拆为两个部分,一部分是网址,另一个部分才是参数,并且必须为其设置报文setHeader,否则服务器是无法找到参数的
本文主要介绍三种发送不同请求:
1)一种是GET方式请求,此时没有发送的报文,但是会有服务器返回值;
2)其余两种是POST请求,都有发送的报文,其中第一种发送的报文是一组json格式的数据(有返回信息);第二种是利用事件循环的方式发送一组json格式数据报文,因为在项目中都是有线程的,如果不利用事件循环进行阻塞,会导致请求无法发出。
三种具体方式见主要代码,最下方的详细代码实现的是get请求,如果想更改其他两种方式,更换startRequest函数即可,但是在使用post事件循环方式时,需要将.h中的startRequest定义更改为
void startRequest(const QString &hostName, const QString &diskName, const QString &diskSize, const QString &mount, const QString &format, const QString &authStatus, const QString &keyfile);
在构造函数中调用时,改为
startRequest("2.3.4.5","dev/sda123","10G","/mnt","ext4","1","this is .key's content");
3、使用前提:一定要注意!!!!!,不然无法与服务器连接
在.pro文件中添加
QT += network
4、get主要代码
void MainWindow::startRequest(const QUrl &requestedUrl){ url = requestedUrl; manager = new QNetworkAccessManager(this); req.setUrl(url); //由于请求发生重定向,所以要加上这行代码,设置自动跳转,否则会返回 302 req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); reply = manager->get(req); connect(reply,&QNetworkReply::finished,this,&MainWindow::replyFinished); }
5、post第一种主要代码
void MainWindow::startRequest(const QUrl &requestedUrl){ url = requestedUrl; //post QByteArray array; json.insert("table_operation","select"); QJsonDocument document; document.setObject(json); array = document.toJson(QJsonDocument::Compact); qDebug()<<"array在转为json后为:"<<array; manager = new QNetworkAccessManager(this); req.setUrl(url); req.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); reply = manager->post(req,array); connect(reply,&QNetworkReply::finished,this,&MainWindow::replyFinished); }
6、post第二种主要代码
void MainWindow::sendRequest(const QString &hostName, const QString &diskName, const QString &diskSize, const QString &mount, const QString &format, const QString &authStatus, const QString &keyfile) { //1.json格式传输报文 QJsonObject json; QJsonDocument jsonDoc; //打包json数据 json["host_name"] = hostName; json["disk_name"] = diskName; json["disk_size"] = diskSize; json["mount"] = mount; json["format"] = format; json["certification_status"] = authStatus; json["keyfile_path"] = keyfile; jsonDoc.setObject(json); QByteArray dataArray = jsonDoc.toJson(QJsonDocument::Compact); qDebug()<< "jsondata组为:"<<dataArray; //2.构造URL&&请求头 QString urlStr = "http://127.0.0.1:8000/test"; qDebug()<<"url地址为:"<<urlStr; url = urlStr; //构造请求头 req.setUrl(url); req.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json;charset=UTF-8")); // req.setRawHeader("Connection", "Keep-Alive"); //3.post数据 manager = new QNetworkAccessManager(this); reply = manager->post(req,dataArray); QEventLoop eventLoop; connect(manager,SIGNAL(finished(QNetworkReply*)),&eventLoop,SLOT(quit())); connect(reply,&QNetworkReply::finished,this,&MainWindow::replyFinished); eventLoop.exec(); }
二、话不多说上详细代码
QT创建一个继承QWidget的Qt Widgets Application就行
1、mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QDebug> #include <QtNetwork> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QNetworkRequest> #include <QTextCodec> #include <QFile> #include <QTextStream> #include <QDateTime> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void startRequest(const QUrl &requestedUrl); private: Ui::MainWindow *ui; private: // [3] 添加对象 QUrl url; QNetworkRequest req; QNetworkReply *reply; QNetworkAccessManager *manager; private slots: // void startRequest(const QUrl &requestedUrl); void replyFinished(); }; #endif // MAINWINDOW_H
2、mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QLabel> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); //调用函数发送请求,参数是请求的服务器地址 startRequest( QUrl("http://127.0.0.1:8000/test")); } MainWindow::~MainWindow() { delete ui; } void MainWindow::startRequest(const QUrl &requestedUrl){ url = requestedUrl; manager = new QNetworkAccessManager(this); req.setUrl(url); //由于请求发生重定向,所以一定要加上这行代码,设置自动跳转,否则会返回 302 req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); // req.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"); // req.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"); //get方式发送请求 reply = manager->get(req); //将服务器的返回信号与replyFinished槽连接起来,当服务器返回消息时,会在槽里做相应操作 connect(reply,&QNetworkReply::finished,this,&MainWindow::replyFinished); } void MainWindow::replyFinished(){ // <1>判断有没有错误 if (reply->error()){ qDebug()<<reply->errorString(); reply->deleteLater(); return; } // <2>检测网页返回状态码,常见是200,404等,200为成功 int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); qDebug() << "statusCode:" << statusCode; // <3>判断是否需要重定向 if (statusCode >= 200 && statusCode <300){ // ok // 准备读数据 QTextCodec *codec = QTextCodec::codecForName("utf8"); QString all = codec->toUnicode(reply->readAll()); qDebug() << "接收到的数据" <<all; //显示在mainwindow 测试,将服务器返回值打印至label上,服务器用的是mongoose模拟 QLabel *label = new QLabel(this); label->setText(all); label->move(200,200); label->setVisible(true); // 数据读取完成之后,清除reply reply->deleteLater(); reply = nullptr; } else if (statusCode >=300 && statusCode <400){ // redirect // 获取重定向信息 const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); // 检测是否需要重定向,如果不需要则读数据 if (!redirectionTarget.isNull()) { const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl()); reply->deleteLater(); reply = nullptr; startRequest(redirectedUrl); qDebug()<< "http redirect to " << redirectedUrl.toString(); return; } } }
3、main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
这个项目的代码是get请求方式,如果要换成post,只需要将startRequest函数换成博客开头提到的【post主要代码】即可;
replyFinished函数是接收服务器返回的状态值和返回值的,可以自己做需要的操作。
三、结果图
1、服务器接收到的POST请求信息:
2、GET请求没有发送报文,但是能收到mongoose模拟服务器的返回值:
四、参考
https://blog.csdn.net/china_jeffery/article/details/83246355
https://blog.csdn.net/qiufenpeng/article/details/81583768
https://www.cnblogs.com/cjdty/p/10659685.html
END