Qt 是一個跨平臺C++圖形介面開發庫,利用Qt可以快速開發跨平臺窗體應用程式,在Qt中我們可以透過拖拽的方式將不同元件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹如何運用QNetworkAccessManager
元件實現Web網頁訪問。
QNetworkAccessManager是Qt網路模組中的關鍵類,用於管理網路訪問和請求。作為一個網路請求的排程中心,它為Qt應用程式提供了傳送和接收各種型別的網路請求的能力,包括常見的GET、POST、PUT、DELETE等。這個模組的核心功能在於透過處理QNetworkReply
和QNetworkRequest
來實現與網路資源的互動。
透過QNetworkAccessManager
,Qt應用程式能夠輕鬆地與遠端伺服器通訊,獲取資料或將資料上傳到伺服器。這種網路請求的管理不僅是非同步的,以確保不會阻塞主執行緒,還提供了豐富的訊號和槽機制,使得開發者可以靈活地處理不同階段的網路操作。
通常,QNetworkAccessManager
會與QNetworkReply
和QNetworkRequest
一起使用。QNetworkRequest
用於封裝和配置網路請求的各種屬性,例如URL、請求頭等。而QNetworkReply
則代表了對網路請求的響應,包含了請求返回的資料和相關資訊。這三者共同協作,為Qt應用程式提供了便捷、靈活且強大的網路通訊能力。
1.1 通用API函式
1.1.1 QNetworkAccessManager
要想實現網路通訊首先需要新建一個網路訪問管理器,以下是QNetworkAccessManager
類中的一些常用函式及其描述:
函式 | 描述 |
---|---|
QNetworkAccessManager(QObject *parent = nullptr) |
建構函式,建立一個QNetworkAccessManager 例項。 |
virtual ~QNetworkAccessManager() |
虛解構函式,釋放QNetworkAccessManager 例項。 |
QNetworkReply *get(const QNetworkRequest &request) |
傳送GET請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *post(const QNetworkRequest &request, QIODevice *data) |
傳送POST請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data) |
傳送POST請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *put(const QNetworkRequest &request, QIODevice *data) |
傳送PUT請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data) |
傳送PUT請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *deleteResource(const QNetworkRequest &request) |
傳送DELETE請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *head(const QNetworkRequest &request) |
傳送HEAD請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = nullptr) |
傳送自定義請求,並返回與請求關聯的QNetworkReply 物件。 |
QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data) |
傳送自定義請求,並返回與請求關聯的QNetworkReply 物件。 |
void setConfiguration(const QNetworkConfiguration &config) |
設定網路配置,用於定製網路行為。 |
QNetworkConfiguration configuration() const |
獲取當前網路配置。 |
void clearAccessCache() |
清除網路訪問快取。 |
void setCache(QAbstractNetworkCache *cache) |
設定網路快取。 |
QAbstractNetworkCache *cache() const |
獲取當前網路快取。 |
void setCookieJar(QNetworkCookieJar *cookieJar) |
設定用於管理HTTP cookie的QNetworkCookieJar 。 |
QNetworkCookieJar *cookieJar() const |
獲取當前的HTTP cookie管理器。 |
這些函式提供了QNetworkAccessManager
的核心功能,使得開發者能夠方便地進行各種型別的網路請求,配置網路引數,並進行相關的網路管理操作。
1.1.2 QNetworkReply
以下是QNetworkReply
類中的一些常用函式及其描述:
函式 | 描述 |
---|---|
QByteArray readAll() const |
讀取所有可用的資料,並返回一個QByteArray ,包含從網路回覆讀取的所有內容。 |
QByteArray peek(int maxSize) const |
檢視最多maxSize 位元組的可用資料,但不從緩衝區中移除。 |
QByteArray read(int maxSize) |
從網路回覆中讀取最多maxSize 位元組的資料,並將其從緩衝區中移除。 |
QByteArray readLine(int maxSize = 0) |
從網路回覆中讀取一行資料,最多包含maxSize 位元組,並將其從緩衝區中移除。 |
void ignoreSslErrors(const QList<QSslError> &errors = QList<QSslError>()) |
忽略SSL錯誤,繼續處理網路回覆。 |
void abort() |
終止網路回覆的處理,關閉底層連線。 |
void close() |
關閉網路回覆的處理。 |
QUrl url() const |
返回與網路回覆相關聯的URL。 |
QNetworkRequest request() const |
返回生成此網路回覆的網路請求。 |
QNetworkAccessManager *manager() const |
返回與網路回覆相關聯的QNetworkAccessManager 。 |
bool isFinished() const |
檢查網路回覆是否已完成。 |
QNetworkReply::NetworkError error() const |
返回網路回覆的錯誤程式碼。 |
bool hasRawHeader(const QByteArray &headerName) const |
檢查網路回覆是否包含指定原始頭。 |
QList<QByteArray> rawHeaderList() const |
返回網路回覆的所有原始頭的列表。 |
QByteArray rawHeader(const QByteArray &headerName) const |
返回指定原始頭的值。 |
QVariant header(QNetworkRequest::KnownHeaders header) const |
返回指定標準頭的值。 |
QList<QByteArray> rawHeaderValues(const QByteArray &headerName) const |
返回指定原始頭的所有值。 |
QVariant attribute(QNetworkRequest::Attribute code) const |
返回指定網路請求屬性的值。 |
QIODevice *readAllStandardOutput() |
讀取標準輸出的所有資料,並返回一個QIODevice ,用於訪問讀取的內容。 |
QIODevice *readAllStandardError() |
讀取標準錯誤的所有資料,並返回一個QIODevice ,用於訪問讀取的內容。 |
bool isReadable() const |
檢查網路回覆是否可讀取。 |
這些函式提供了對QNetworkReply
例項進行各種操作和查詢的方法,包括讀取回複資料、處理SSL錯誤、獲取請求資訊、檢查錯誤狀態等。開發者可以根據具體需求使用這些函式來有效地與網路回覆進行互動。
1.1.3 QNetworkRequest
以下是QNetworkRequest
類中的一些常用函式及其描述:
函式 | 描述 |
---|---|
QNetworkRequest(const QUrl &url) |
使用給定的URL構造一個QNetworkRequest 例項。 |
void setUrl(const QUrl &url) |
設定QNetworkRequest 的URL。 |
QUrl url() const |
返回與QNetworkRequest 相關聯的URL。 |
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue) |
設定指定原始頭的值。 |
QByteArray rawHeader(const QByteArray &headerName) const |
返回指定原始頭的值。 |
bool hasRawHeader(const QByteArray &headerName) const |
檢查QNetworkRequest 是否包含指定原始頭。 |
void setRawHeaderList(const QList<QByteArray> &headerList) |
設定所有原始頭的列表。 |
QList<QByteArray> rawHeaderList() const |
返回QNetworkRequest 的所有原始頭的列表。 |
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) |
設定指定標準頭的值。 |
QVariant header(QNetworkRequest::KnownHeaders header) const |
返回指定標準頭的值。 |
void setAttribute(QNetworkRequest::Attribute code, const QVariant &value) |
設定指定網路請求屬性的值。 |
QVariant attribute(QNetworkRequest::Attribute code) const |
返回指定網路請求屬性的值。 |
void setSslConfiguration(const QSslConfiguration &config) |
設定SSL配置。 |
QSslConfiguration sslConfiguration() const |
返回SSL配置。 |
void setMaximumRedirectsAllowed(int maxRedirects) |
設定允許的最大重定向次數。 |
int maximumRedirectsAllowed() const |
返回允許的最大重定向次數。 |
void setOriginatingObject(QObject *object) |
設定發起此網路請求的物件。 |
QObject *originatingObject() const |
返回發起此網路請求的物件。 |
bool isEmpty() const |
檢查QNetworkRequest 是否為空(未設定URL)。 |
這些函式提供了對QNetworkRequest
例項進行各種操作和查詢的方法,包括設定和獲取頭資訊、設定SSL配置、設定和獲取網路請求屬性等。開發者可以根據具體需求使用這些函式來有效地構建和管理網路請求。
1.2 實現Web頁面訪問
要使用該模組讀者應該在*.pro
檔案內包含network
網路模組,並在標頭檔案中引入QNetworkAccessManager
、QNetworkReply
、QNetworkRequest
三個類,在建立訪問時首先使用QNetworkAccessManager
新增一個manager
管理類,並透過QNetworkRequest
類建立一個GET請求地址,透過使用manager.get
方法實現對特定頁面的訪問。
當訪問完成時需要透過一個訊號來實現對資料的處理,在QNetworkReply
類中包含有如下表所示的訊號以供讀者使用,例如當訪問被完成時則自動觸發&QNetworkReply::finished
完成訊號,此時只需要對該訊號進行相應的處理即可,通常會使用一個槽函式來處理它。
訊號 | 描述 |
---|---|
finished() |
當網路請求完成時發出。 |
downloadProgress(qint64, qint64) |
在下載過程中定期發出,提供下載進度資訊。引數為已下載的位元組數和總位元組數。 |
uploadProgress(qint64, qint64) |
在上傳過程中定期發出,提供上傳進度資訊。引數為已上傳的位元組數和總位元組數。 |
readyRead() |
當有可讀取的資料時發出,用於通知應用程式可以呼叫readAll() 或read() 方法以獲取更多資料。 |
error(QNetworkReply::NetworkError) |
當網路請求發生錯誤時發出,引數為錯誤程式碼。 |
sslErrors(const QList<QSslError> &) |
當SSL錯誤發生時發出,引數為SSL錯誤的列表。 |
這些訊號提供了豐富的資訊,使開發者能夠在不同階段處理網路請求。同理,在下載和上傳過程中可以使用downloadProgress
和uploadProgress
訊號來獲取進度資訊,readyRead
訊號表示有可讀取的資料,error
訊號表示請求發生錯誤,sslErrors
訊號表示SSL
相關的錯誤。
當訊號被觸發時則會透過QObject::connect
連線到對應的槽函式上,如下案例中所示,在槽函式內透過reply->attribute
方法我們獲取到此次響應碼中的QNetworkRequest::HttpStatusCodeAttribute
屬性,該屬性用來指明本次訪問的狀態值。此類屬性也有許多可供參考,如下所示;
屬性 | 描述 |
---|---|
QNetworkRequest::HttpStatusCodeAttribute |
HTTP響應的狀態碼。 |
QNetworkRequest::HttpReasonPhraseAttribute |
HTTP響應的原因短語,如"OK"、"Not Found"等。 |
QNetworkRequest::RedirectionTargetAttribute |
重定向目標的URL。 |
QNetworkRequest::ConnectionEncryptedAttribute |
連線是否加密的標誌,返回一個bool 值。 |
QNetworkRequest::SourceIsFromCacheAttribute |
請求是否來自快取的標誌,返回一個bool 值。 |
QNetworkRequest::HttpPipeliningAllowedAttribute |
是否允許HTTP流水線傳輸的標誌,返回一個bool 值。 |
QNetworkRequest::HttpPipeliningWasUsedAttribute |
是否使用了HTTP流水線傳輸的標誌,返回一個bool 值。 |
QNetworkRequest::CustomVerbAttribute |
自定義請求動作(HTTP verb)的字串。 |
QNetworkRequest::User |
使用者自定義的屬性,用於儲存任意型別的使用者資料。 |
這些屬性提供了額外的資訊,使得開發者能夠更全面地瞭解和處理網路響應。根據具體的應用需求,開發者可以選擇使用這些屬性中的一個或多個來獲取所需的資訊。
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 建立網路訪問管理器
QNetworkAccessManager manager;
// 建立GET請求
QNetworkRequest request(QUrl("http://www.baidu.com"));
// 傳送GET請求
QNetworkReply *reply = manager.get(request);
// 連線訊號槽,處理響應
QObject::connect(reply, &QNetworkReply::finished, [&]()
{
if (reply->error() == QNetworkReply::NoError)
{
// 獲取請求的 URL
qDebug() << "Request URL:" << reply->request().url();
// 輸出請求頭資訊
qDebug() << "Request Headers:";
QList<QByteArray> requestHeaders = reply->request().rawHeaderList();
foreach (const QByteArray &header, requestHeaders) {
qDebug() << header << ":" << reply->request().rawHeader(header);
}
// 獲取響應碼
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "HttpStatusCodeAttribute:" << statusCode;
// 連線是否加密的標誌
bool connectionEncryptedAttribute = reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool();
qDebug() << "ConnectionEncryptedAttribute:" << connectionEncryptedAttribute;
// 請求是否來自快取的標誌
bool sourceIsFromCacheAttribute = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
qDebug() << "SourceIsFromCacheAttribute:" << sourceIsFromCacheAttribute;
// HTTP請求是否被允許進行流水線處理的標誌
bool httpPipeliningAllowedAttribute = reply->attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool();
qDebug() << "HttpPipeliningAllowedAttribute:" << httpPipeliningAllowedAttribute;
// 輸出響應頭資訊
qDebug() << "Response Headers:";
QList<QByteArray> responseHeaders = reply->rawHeaderList();
foreach (const QByteArray &header, responseHeaders) {
qDebug() << header << ":" << reply->rawHeader(header);
}
// 處理響應內容,這裡可以使用 readAll() 方法獲取響應內容
// qDebug() << "Response Content:" << reply->readAll();
} else
{
qDebug() << "Error:" << reply->errorString();
}
// 釋放資源
reply->deleteLater();
QCoreApplication::quit();
});
return a.exec();
}
讀者可自行編譯並執行這段程式碼,觀察請求與相應資料如下圖所示;
至於如何在圖形介面中使用則就更簡單了,首先我們在mainwindow.h
標頭檔案中定義好所需要的兩個槽函式,函式on_finished()
用於在完成請求後被呼叫,函式on_readyRead()
則用於在回撥被執行後呼叫,並並以兩個網路管理類的指標變數,如下所示;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
//自定義槽函式
void on_finished();
void on_readyRead();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QNetworkAccessManager networkManager; // 網路管理
QNetworkReply *reply; // 網路響應
};
當獲取按鈕被點選後則開始執行讀入指定URL地址,並對該地址進行網頁訪問,同時繫結這兩個訊號,一旦被觸發則自動路由到對應的槽函式上面去,如下所示;
void MainWindow::on_pushButton_clicked()
{
// 讀入URL地址
QString urlSpec = ui->lineEdit->text().trimmed();
if (urlSpec.isEmpty())
{
QMessageBox::information(this, "錯誤", "請指定URL");
return;
}
// 格式化URL
QUrl newUrl = QUrl::fromUserInput(urlSpec);
if (!newUrl.isValid())
{
QMessageBox::information(this, "錯誤", QString("無效URL: %1").arg(urlSpec));
return;
}
// 訪問頁面
reply = networkManager.get(QNetworkRequest(newUrl));
// 完成時的槽函式繫結
connect(reply, SIGNAL(finished()), this, SLOT(on_finished()));
// 讀入資料的槽函式繫結
connect(reply, SIGNAL(readyRead()), this, SLOT(on_readyRead()));
}
相對應的,在on_finished()
槽函式中我們將響應頭讀出並輸出到文字框中,在on_readyRead()
槽函式中則是對整個網站頁面原始碼的輸出功能,完整程式碼如下所示;
void MainWindow::on_finished()
{
// 獲取響應碼
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if(statusCode == 200)
{
ui->plainTextEdit_2->appendPlainText("響應頭資料:");
// 輸出響應頭資訊
QList<QByteArray> responseHeaders = reply->rawHeaderList();
foreach (const QByteArray &header, responseHeaders)
{
ui->plainTextEdit_2->appendPlainText(header + " : " + reply->rawHeader(header));
}
}
}
// 讀入頁面原始碼
void MainWindow::on_readyRead()
{
ui->plainTextEdit->setPlainText(reply->readAll());
}
執行程式碼,讀者可自行輸入特定的網站進行讀取測試,如下所示(完整程式碼請參考課件部分);