Qt 使用QNetworkAccessManager實現Http操作


介紹

QtNetwork是Qt網絡操作模塊,提供了基於TCP/IP的各種API。

qt4x分別使用QFtp和QHttp,5以后統一用QNetworkAccessManager

HTTP請求方法

根據HTTP標准,HTTP請求可以使用多種請求方法。

HTTP1.0定義了三種請求方法: GET, POST 和 HEAD方法。

HTTP1.1新增了五種請求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

序號 方法 描述
1 GET 請求指定的頁面信息,並返回實體主體。
2 HEAD 類似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭
3 POST 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
4 PUT 從客戶端向服務器傳送的數據取代指定的文檔的內容。
5 DELETE 請求服務器刪除指定的頁面。
6 CONNECT HTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器。
7 OPTIONS 允許客戶端查看服務器的性能。
8 TRACE 回顯服務器收到的請求,主要用於測試或診斷。

QNetworkAccessManager接口介紹

接口很多,就不全部復制過來了,如果機器裝着qt5,可以直接在助手看。

可以一目了然的看到幾個熟悉詞匯的api:post、get、put、head,當然還有幾個cookie相關的方法。

 1 QNetworkReply *get(const QNetworkRequest &request)  2 QNetworkReply *head(const QNetworkRequest &request)  3 bool isStrictTransportSecurityEnabled() const
 4 bool isStrictTransportSecurityStoreEnabled() const
 5 NetworkAccessibility networkAccessible() const
 6 QNetworkReply *post(const QNetworkRequest &request, QIODevice *data)  7 QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data)  8 QNetworkReply *post(const QNetworkRequest &request, QHttpMultiPart *multiPart)  9 QNetworkProxy proxy() const
10 QNetworkProxyFactory *proxyFactory() const
11 QNetworkReply *put(const QNetworkRequest &request, QIODevice *data) 12 QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data) 13 QNetworkReply *put(const QNetworkRequest &request, QHttpMultiPart *multiPart)

可以發現使用manager還需要幾個類:QNetworkRequest 專門用於請求的,QNetworkReply 接收請求的響應

QNetworkRequest

1 void setAttribute(Attribute code, const QVariant &value) 2 void setHeader(KnownHeaders header, const QVariant &value) 3 void setMaximumRedirectsAllowed(int maxRedirectsAllowed) 4 void setOriginatingObject(QObject *object) 5 void setPriority(Priority priority) 6 void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue) 7 void setSslConfiguration(const QSslConfiguration &config) 8 void setUrl(const QUrl &url)

主要就是這幾個寫方法,分別對一個請求的不同類進行配置。

客戶端發送一個HTTP請求到服務器的請求消息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求數據四個部分組成,下圖給出了請求報文的一般格式。請求行組成:請求方法+空格+url+空格+協議版本+回車符+換行符。

對於header,qt提供了一個枚舉類型KnownHeaders分別表示不同項:

Constant Value Description
QNetworkRequest::ContentDispositionHeader 6 Corresponds to the HTTP Content-Disposition header and contains a string containing the disposition type (for instance, attachment) and a parameter (for instance, filename).
QNetworkRequest::ContentTypeHeader 0 Corresponds to the HTTP Content-Type header and contains a string containing the media (MIME) type and any auxiliary data (for instance, charset).
QNetworkRequest::ContentLengthHeader 1 Corresponds to the HTTP Content-Length header and contains the length in bytes of the data transmitted.
QNetworkRequest::LocationHeader 2 Corresponds to the HTTP Location header and contains a URL representing the actual location of the data, including the destination URL in case of redirections.
QNetworkRequest::LastModifiedHeader 3 Corresponds to the HTTP Last-Modified header and contains a QDateTime representing the last modification date of the contents.
QNetworkRequest::CookieHeader 4 Corresponds to the HTTP Cookie header and contains a QList<QNetworkCookie> representing the cookies to be sent back to the server.
QNetworkRequest::SetCookieHeader 5 Corresponds to the HTTP Set-Cookie header and contains a QList<QNetworkCookie> representing the cookies sent by the server to be stored locally.
QNetworkRequest::UserAgentHeader 7 The User-Agent header sent by HTTP clients.
QNetworkRequest::ServerHeader 8 The Server header received by HTTP clients.

請求類主要是進行對於地址,還給出了QUrl 類,詳情見后。

QNetworkReply

此類繼承自QIODevice,可使用QIODevice的所有接口,包括readall讀取接收的所有信息。

同時此類提供了finished信號,在響應完斥候發出此信號,可關聯自定義槽函數函數,做響應處理。

提供了attribute屬性函數,可以判斷響應的類型,比如RedirectionTargetAttribute是目標url告知進行重定向

QNetworkReply不會自動釋放空間,一定要主動處理內存釋放,可以調用QObject::deleteLater令其自動釋放空間

范例

.h文件

 1 #ifndef MAINWINDOW_H  2 #define MAINWINDOW_H
 3 
 4 #include <QMainWindow>
 5 #include <QtNetwork>
 6 #include <QFile>
 7 namespace Ui {  8 class MainWindow;  9 } 10 
11 class MainWindow : public QMainWindow { 12  Q_OBJECT 13 
14 public: 15     explicit MainWindow(QWidget *parent = 0); 16     ~MainWindow(); 17     void Get(QUrl u); 18 private slots: 19     void on_pushButton_clicked(); 20     void finished(); 21 private: 22     Ui::MainWindow *ui; 23  QNetworkAccessManager manager; 24  QUrl url; 25     QNetworkReply *reply; 26  QString html_text; 27 }; 28 
29 #endif // MAINWINDOW_H

.cpp文件

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 
 4 MainWindow::MainWindow(QWidget *parent) :  5  QMainWindow(parent),  6     ui(new Ui::MainWindow) {  7     ui->setupUi(this);  8     reply = Q_NULLPTR;  9 } 10 
11 MainWindow::~MainWindow() { 12     delete ui; 13 } 14 
15 void MainWindow::Get(QUrl u) { 16  QNetworkRequest request; 17     url=u; 18  request.setUrl(url); 19     if(reply != Q_NULLPTR) {//更改reply指向位置錢一定要保證之前的定義了自動delete
20         reply->deleteLater(); 21  } 22     reply = manager.get(request); 23     qDebug() << "start get"; 24     connect(reply, &QNetworkReply::finished, this, &MainWindow::finished); 25 } 26 
27 void MainWindow::on_pushButton_clicked() { 28     html_text = ""; 29     Get(QUrl("https://www.baidu.com/")); 30 
31 } 32 
33 void MainWindow::finished() { 34     QByteArray bytes = reply->readAll(); 35     const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); 36     reply->deleteLater(); 37     reply = Q_NULLPTR; 38     if (!redirectionTarget.isNull()) {//如果網址跳轉重新請求
39         const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl()); 40         qDebug()<<"redirectedUrl:"<<redirectedUrl.url(); 41  Get(redirectedUrl); 42         return; 43  } 44     qDebug()<<"finished"; 45     html_text = bytes; 46     qDebug()<<"get ready,read size:"<<html_text.size(); 47 // QFile f("result.html");//寫出文件 48 // f.open(QFile::WriteOnly); 49 // f.write(bytes); 50 // f.close();
51 }

程序很簡單 on_pushButton_clicked 作為范例的入口,當點擊按鈕時開始訪問,會傳遞百度的網址的到Get函數。

get函數中進行get操作,並把返回值的reply connect到finished槽。

finished中首先判斷響應頭是否有重定向要求,如果有重定向則銷毀當前reply並利用指定的新地址重新調用get,可以試驗“www.sina.com”會指向”www.sina.com.cn”

最后通過readll讀取所有數據並保存到文件,雙擊打開文件可以看到效果。當然不會包含圖片信息

其他

post使用

post其實和get類似,只不過同時還傳遞了串數據

post(request, data)即可,其他操作完全一樣

QUrlQuery

對於上述指令直接使用QUrl賦值也是可以的,但是如果后續參數一直在變動,需要自己封裝一個字符串拼接的過程。簡單的辦法是使用QUrlQuery

 1 QUrl url("https://techieliang.com/wp-admin/post.php");  2 QUrlQuery tt;  3 tt.addQueryItem("post","000");  4 tt.addQueryItem("action","edit");  5 tt.addQueryItem("name","techieliang");  6 url.setQuery(tt);  7 qDebug()<<url.url();  8 tt.clear();  9 tt.addQueryItem("post","000"); 10 url.setQuery(tt); 11 qDebug()<<url.url(); 12 url.setUrl("https://techieliang.com/wp-admin/post.php?"); 13 qDebug()<<url.url(); 14 url.setQuery(tt); 15 qDebug()<<url.url();

結果

1 "https://techieliang.com/wp-admin/post.php?post=000&action=edit&name=techieliang"
2 "https://techieliang.com/wp-admin/post.php?post=000"
3 "https://techieliang.com/wp-admin/post.php?"
4 "https://techieliang.com/wp-admin/post.php?post=000"
  • setUrl會將Url改為新值,並清空Query,直接更改url后需要重新setQuery
  • setQuery不會改變Url值,可以不斷的setQuery去構造不同的參數
  • QUrl會自動處理url后的?若setUrl的值末尾沒有?會自動在url和query之間增加,若已經包含則不會重復


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM