HTTP協議?
HTTP(HyperText Transfer Protocol,超文本傳輸協議)是互聯網上應用最為廣泛的協議之一,用于客戶端和服務器之間的通信。默認端口80,傳輸層使用的是TCP協議
特點
無連接:HTTP協議是無連接的,這意味著每次請求 - 響應完成后,連接就會關閉。客戶端和服務器之間不會保持持久連接。
無狀態:HTTP協議是無狀態的,服務器不會保存客戶端請求之間的狀態信息。每次請求都是獨立的,服務器不會記住之前客戶端的請求內容,除非通過其他機制(如Cookie)來實現狀態管理。
協議格式:
HTTP 請求
請求行:包含請求方法、請求URI和HTTP協議版本。常見的請求方法有:
GET:用于請求服務器返回指定資源的內容。例如,當你在瀏覽器中輸入網址并回車時,瀏覽器會發送一個GET請求到服務器,請求該網址對應的網頁內容。
POST:用于向服務器提交數據,通常用于表單提交。例如,當你在登錄頁面輸入用戶名和密碼并點擊“登錄”按鈕時,瀏覽器會發送一個POST請求,將用戶名和密碼數據提交給服務器。
PUT:用于向服務器上傳整個資源,通常用于更新資源。
DELETE:用于請求服務器刪除指定的資源。
HEAD:與GET方法類似,但它只返回響應頭,不返回響應體內容,常用于檢查資源是否存在。
OPTIONS:用于獲取服務器支持的HTTP方法。
CONNECT:用于建立隧道,常用于代理服務器。
TRACE:用于回顯請求的內容,主要用于調試。
請求頭:包含客戶端向服務器發送的附加信息,例如:
Host:指定請求的主機名和端口號。
User-Agent:標識客戶端的類型(如瀏覽器版本、操作系統等)。
Accept:告訴服務器客戶端可以接受的內容類型(如HTML、JSON等)。
Content-Type:用于POST或PUT請求,指定請求體的媒體類型(如
application/json
、application/x-www-form-urlencoded
等)。Cookie:用于在客戶端和服務器之間傳遞狀態信息。
空行:表示請求頭部的結束。
請求體:對于POST、PUT等方法,請求體中包含要提交給服務器的數據,如表單數據或JSON格式的數據。
HTTP 響應
狀態行:包含HTTP協議版本、狀態碼和狀態消息。狀態碼是一個三位數字,用于表示請求的結果:
1xx:信息性狀態碼,表示請求已被接收,繼續處理。例如,
100 Continue
表示客戶端應繼續發送請求的其余部分。2xx:成功狀態碼,表示請求已成功處理。例如,
200 OK
表示請求正常處理成功;201 Created
表示請求成功并且服務器創建了新的資源。3xx:重定向狀態碼,表示需要進一步的操作以完成請求。例如,
301 Moved Permanently
表示請求的資源已被永久移動到新的URL;302 Found
表示請求的資源臨時移動到新的URL。4xx:客戶端錯誤狀態碼,表示客戶端發送的請求有語法錯誤或無法完成請求。例如,
400 Bad Request
表示請求語法有誤;401 Unauthorized
表示請求未授權;404 Not Found
表示請求的資源不存在。5xx:服務器錯誤狀態碼,表示服務器在處理請求的過程中發生了錯誤。例如,
500 Internal Server Error
表示服務器內部錯誤;503 Service Unavailable
表示服務器暫時無法處理請求。
響應頭:包含服務器向客戶端發送的附加信息,例如:
Content-Type:指定響應體的媒體類型(如
text/html
、application/json
等)。Content-Length:指定響應體的長度(以字節為單位)。
Set-Cookie:用于設置Cookie,將狀態信息發送到客戶端。
Location:用于重定向,指定新的資源位置。
空行:表示請求頭部的結束。
響應體:包含服務器返回給客戶端的資源內容,如網頁HTML代碼、圖片數據等。
URL(統一資源定位符)
URI:統一資源標識符,用于唯一標識資源,是一個更廣泛的術語。
URL:統一資源定位符,是URI的一個子集,用于標識資源的具體位置,可以直接用于訪問資源
結構? ?scheme://authority/path[?query][#fragment]
fragment:片段標識符,通常用于標識資源內部的某個部分。
query:查詢參數,用于向服務器傳遞額外的信息。
path:資源的路徑,通常是一個層次化的路徑結構。
authority:資源所在的主機名或IP地址,可選地包括端口號。
scheme:協議類型,如
http
、https
、ftp
等。eg: http://127.0.0.1:8080/?wd=%E4%B8%AD%E5%9B%BD
URL編碼通常也被稱為百分號編碼(URL?Encoding,also known as percent-encoding) ,是因為它的編碼方式非常簡單,使用%百分號加上兩位的字符代表一個字節的十六進制形式 。
在 URI 中,某些字符具有特殊含義:
/
表示路徑分隔符?
表示查詢字符串的開始&
用于分隔查詢參數=
用于分隔參數名和參數值URN:統一資源名稱,也是URI的一種形式,用于標識資源的名稱,而不是位置。
HTTPS(HTTP Secure)
HTTPS是HTTP的安全版本,通過在HTTP協議的基礎上添加SSL/TLS(Secure Sockets Layer/Transport Layer Security)加密層來實現安全通信。它能夠防止數據在傳輸過程中被竊聽、篡改或偽造。默認端口為443。
HTTPS的實現過程包括證書的頒發和驗證。服務器需要向證書頒發機構(CA)申請SSL證書,客戶端在與服務器建立HTTPS連接時會驗證服務器的證書是否有效。如果證書無效(如證書過期、證書頒發機構不可信等),瀏覽器會提示用戶連接不安全。
HTTP / 網絡請求類
QNetworkAccessManager類
基于事件驅動模型,通過信號和槽機制處理異步網絡操作,不會阻塞主線程
Network Access?
API是圍繞一個QNetworkAccessManager對象構建的,該對象為它發送的請求保存通用配置和設置。它包含代理和緩存配置,以及與這些問題相關的信號,以及可用于監視網絡操作進度的應答信號。對于整個Qt應用程序,一個QNetworkAccessManager實例應該足夠了。因為QNetworkAccessManager是基于QObject的,所以它只能在它所屬的線程中使用。一旦創建了QNetworkAccessManager對象,應用程序就可以使用它通過網絡發送請求。提供了一組標準函數,它們接受一個請求和可選數據,每個函數返回一個QNetworkReply對象。返回的對象用于獲取響應相應請求而返回的任何數據。
QNetworkAccessManager有一個異步API。當調用上面的replyFinished槽時,它接受的參數是QNetworkReply對象,該對象包含下載的數據以及元數據(報頭等)。
注意:請求完成后,用戶有責任在適當的時候刪除QNetworkReply對象。不要直接在連接finished()的槽內刪除。您可以使用deleteLater()函數。
注意:QNetworkAccessManager對它接收到的請求進行排隊。并行執行的請求數量取決于協議。目前,對于桌面平臺上的HTTP協議,一個主機/端口組合并行執行6個請求。
QNetworkAccessManager
?與以下類配合使用:
QNetworkRequest
:封裝請求信息(URL、請求頭、超時等)QNetworkReply
:封裝響應結果(返回數據、狀態碼、錯誤信息等)QUrl
:處理 URL 解析QByteArray
:存儲請求 / 響應數據
常用方法:
發送請求
get(const QNetworkRequest &request):發送 GET 請求
post(const QNetworkRequest &request, const QByteArray &data):發送 POST 請求(表單數據)
post(const QNetworkRequest &request, QIODevice *data):發送 POST 請求(大文件 / 流數據)
put()/deleteResource():對應 HTTP 的 PUT 和 DELETE 方法配置網絡
setProxy(const QNetworkProxy &proxy):設置代理
setCookieJar(QNetworkCookieJar *jar):設置 Cookie 容器
setCache(QNetworkCache *cache):設置緩存信號與槽
finished(QNetworkReply *):請求完成時觸發(成功或失敗)
downloadProgress(qint64 bytesReceived, qint64 bytesTotal):下載進度更新
uploadProgress(qint64 bytesSent, qint64 bytesTotal):上傳進度更新
sslErrors(QNetworkReply *, const QList<QSslError> &):SSL 證書錯誤時觸發
注意事項
- 異步處理:所有請求都是異步的,需通過?
finished
?信號處理結果,避免阻塞 UI - 資源釋放:
QNetworkReply
?對象必須通過?deleteLater()
?釋放,否則會導致內存泄漏 - HTTPS 支持:需要在項目文件(
.pro
)中添加?QT += network
,并確保系統支持 SSL(可能需要額外的庫,如 OpenSSL) - 超時設置:Qt 沒有直接設置超時的方法,可通過?
QTimer
?實現 - 大文件下載:應通過?
readyRead
?信號分塊讀取數據,避免一次性加載到內存
QNetworkRequest類
QNetworkRequest is part of the Network Access API and is the class holding the information necessary to send a request over the network. ?It contains a URL and some ancillary information that can be used to modify the request.
QNetworkRequest是Network Access API的一部分,它是包含通過網絡發送請求所需信息的類。它包含一個URL和一些可用于修改請求的輔助信息。
主要功能與用途
- 封裝請求 URL:明確網絡請求的目標地址,支持 HTTP、HTTPS、FTP 等多種協議。
- 設置請求頭:可以添加各種 HTTP 頭信息,如?
User-Agent
(用于標識客戶端身份)、Content-Type
(指定請求體的類型,如表單數據、JSON 數據等)、Authorization
(用于身份驗證,如 Token 認證) 等。 - 管理緩存策略:控制請求的緩存行為,例如設置是否從緩存中讀取數據,以及是否將響應數據緩存起來。
- 處理重定向:可以配置對重定向的處理方式,決定是否自動跟隨重定向請求
常用方法:
常用構造函數
QNetworkRequest():默認構造函數,創建一個空的請求對象
QNetworkRequest(const QUrl &url):根據給定的 QUrl 創建一個請求對象
將請求的目標地址設置為該 QUrl設置 URL
setUrl(const QUrl &url):設置請求的目標 URL
url() const:獲取請求的目標 URL設置請求頭
setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value):
設置已知類型的請求頭,KnownHeaders 是一個枚舉類型,包含了常見的 HTTP 頭,
比如 ContentTypeHeader(內容類型頭)、UserAgentHeader(用戶代理頭) 等。
setRawHeader(const QByteArray &name, const QByteArray &value):設置自定義的原始請求頭
header(QNetworkRequest::KnownHeaders header) const:獲取已知類型的請求頭的值
rawHeader(const QByteArray &name) const:獲取自定義的原始請求頭的值緩存相關
setCacheMetaData(const QNetworkCacheMetaData &metaData):設置請求的緩存元數據
cacheMetaData() const:獲取請求的緩存元數據
setCachePolicy(QNetworkRequest::CachePolicy cachePolicy):
設置請求的緩存策略
常見的緩存策略包括 NoCache(不使用緩存)、PreferCache(優先使用緩存)等
cachePolicy() const:獲取請求的緩存策略重定向相關
setRedirectPolicy(QNetworkRequest::RedirectPolicy redirectPolicy):
設置重定向策略
例如 ManualRedirectPolicy(手動處理重定向)、AutoRedirectPolicy(自動跟隨重定向)
redirectPolicy() const:獲取請求的重定向策略
QNetworkReply類
QNetworkReply類包含與QNetworkAccessManager發布的請求相關的數據和元數據。與QNetworkRequest一樣,它包含一個URL和報頭(包括解析格式和原始格式)、一些關于應答狀態的信息和應答本身的內容。
QNetworkReply是一個順序訪問的QIODevice,這意味著一旦從對象中讀取數據,它就不再被設備保存。因此,如果需要,應用程序有責任保留這些數據。每當從網絡接收并處理更多數據時,就會發出readyRead()信號。
當接收到數據時,也會發出downloadProgress()信號,但是如果對內容進行了任何轉換(例如,解壓縮和刪除協議開銷),則其中包含的字節數可能不代表接收到的實際字節數。
盡管QNetworkReply是連接到應答內容的QIODevice,但它也會發出uploadProgress()信號,該信號指示具有此類內容的操作的上傳進度。
注意:不要刪除errorOccurred()或finished()信號所連接槽位中的對象。使用deleteLater()。
主要功能與特性
- 封裝服務器返回的響應數據(文本、二進制等)
- 提供請求的狀態信息(成功 / 失敗、HTTP 狀態碼等)
- 支持獲取響應頭、Cookie 等元數據
- 提供上傳 / 下載進度通知
- 支持中斷請求、處理重定向等操作
常用方法:
獲取響應數據
readAll():讀取所有響應數據(QByteArray 類型),適合處理小數據
read(qint64 maxSize):讀取指定大小的數據,適合大文件分塊處理
readyRead() 信號:有新數據可讀時觸發(用于異步分塊讀取)狀態與錯誤處理
error():返回錯誤類型(QNetworkReply::NetworkError 枚舉),NoError 表示成功
errorString():返回錯誤的描述信息(字符串)
isFinished():判斷請求是否已完成
isRunning():判斷請求是否正在進行HTTP 響應信息
attribute(QNetworkRequest::Attribute code):獲取響應屬性
如 HTTP 狀態碼:
常見狀態碼:200(成功)、404(未找到)、500(服務器錯誤)等
rawHeaderList():獲取所有響應頭的名稱列表
rawHeader(const QByteArray &headerName):獲取指定響應頭的值(如 Content-Type)控制請求
abort():中斷當前請求
ignoreSslErrors():忽略 SSL 證書錯誤(謹慎使用,可能有安全風險)信號與槽
finished():請求完成時觸發(無論成功或失敗)
readyRead():有新數據可讀時觸發(用于分塊讀取)
downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
下載進度更新(bytesTotal 為 -1 表示未知大小)
uploadProgress(qint64 bytesSent, qint64 bytesTotal):上傳進度更新
sslErrors(const QList<QSslError> &errors):SSL 證書驗證失敗時觸發
?成果展示:
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QUrl>
#include <QNetworkReply>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);networkAccessManger = new QNetworkAccessManager(this);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_GET_clicked()
{QUrl url("http://127.0.0.1:8080/work/worktask/work.json");QNetworkRequest request(url);//發送GET請求QNetworkReply *reply = networkAccessManger->get(request);//連接響應完成信號connect(reply, &QNetworkReply::finished, this, [=](){if(reply->error() == QNetworkReply::NoError){qDebug() << "success GET";}else{//處理錯誤qDebug() << "Error:" << reply->errorString();}reply->deleteLater(); //釋放資源});connect(reply, &QNetworkReply::readyRead, this, [=](){//處理成功響應QByteArray data = reply->readAll();qDebug() << "GETdata:\n" << data;});
}void MainWindow::on_POST_clicked()
{QByteArray data;//數據以json格式傳輸/** json數據格式* {* "username":"xiaowang",* "password":"123456",* }*///QString paramsdata("{\"username\":\"xiaowang\",\"pasword\":\"123456\"}");QString paramsdata("username=xiaowang&pasword=123456");data = paramsdata.toUtf8();QUrl url;url.setScheme("http");url.setHost("127.0.0.1");url.setPort(8080);url.setPath("/work/worktask/work.json");QNetworkRequest request(url);//設置請求頭//json格式request.setRawHeader("content-type","application/json");//表單格式//request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");QNetworkReply *reply = networkAccessManger->post(request,data);//連接完成信號//連接響應完成信號connect(reply, &QNetworkReply::finished, this, [=](){if(reply->error() == QNetworkReply::NoError){qDebug() << "success GET";}else{//處理錯誤qDebug() << "Error:" << reply->errorString();}reply->deleteLater(); //釋放資源});connect(reply, &QNetworkReply::readyRead, this, [=](){//處理成功響應QByteArray data = reply->readAll();qDebug() << "GETdata:\n" << data;});
}
利用HFS搭建一個簡易服務器進行測試?
?
JSON格式
JSON格式基礎概述
JSON 數據由鍵值對組成,遵循以下規則:
數據由鍵值對組成:
鍵(Key)必須是字符串類型,且必須用雙引號(
"
)括起來值(Value)可以是以下類型之一:
字符串(用雙引號括起來)
數字(整數或浮點數)
布爾值(
true
或false
)數組(用方括號
[]
括起來)對象(用大括號
{}
括起來)null
(表示空值)
鍵值對之間用逗號(
,
)分隔對象用大括號(
{}
)括起來數組用方括號(
[]
)括起來
JSON 數據可以分為兩種主要結構:
對象(Object):
用大括號
{}
括起來,包含一系列鍵值對鍵是字符串,值可以是任何合法的 JSON 數據類型
數組(Array):
用方括號
[]
括起來,包含一系列值數組中的值可以是任何合法的 JSON 數據類型
eg:
{"name": "張三","age": 25,"isStudent": false,"address": {"street": "北京市海淀區中關村大街1號","city": "北京","postalCode": "100080"},"hobbies": ["閱讀", "編程", "旅行"] }
["蘋果","香蕉","橙子" ]
JSON 的優點
輕量級:JSON 數據格式簡潔,易于傳輸
易于閱讀和編寫:JSON 數據格式接近人類可讀的文本格式
語言無關:雖然 JSON 的語法來源于 JavaScript,但它獨立于語言,可以被多種編程語言解析和生成
易于解析:大多數編程語言都提供了內置的 JSON 解析和生成工具
Qt中解析JSON數據
在 Qt 中解析 JSON 數據可以使用 Qt 自帶的 JSON 模塊,該模塊提供了許多類來處理 JSON 數據。
JsonDocument
fromJson(const QByteArray &data, QJsonParseError *error = nullptr) const
將 JSON 格式的字節數組解析為QJsonDocument對象,error參數用于接收解析錯誤信息
toJson(JsonFormat format = Indented)
將QJsonDocument轉換為 JSON 格式的字節數組
format可指定縮進(Indented)或緊湊(Compact)格式QJsonObject
contains(const QString &key):判斷是否包含指定鍵
value(const QString &key):獲取指定鍵對應的QJsonValue
keys():返回所有鍵的列表
toVariantMap():將 JSON 對象轉換為QVariantMap(便于快速訪問)QJsonArray
size():返回數組元素數量
at(int i):獲取索引i處的QJsonValue
foreach 遍歷:循環訪問數組元素
toVariantList():轉換為QVariantListQJsonValue
類型判斷:isString()、isDouble()、isBool()、isObject()、isArray()、isNull()
類型轉換:toString()、toDouble()、toBool()、toObject()、toArray()從文件讀取 JSON(QFile + 異步文件操作)
QFile本身是同步的,但可結合QFileSystemWatcher監控文件變化,觸發解析:
QFileSystemWatcher::fileChanged(const QString &path)
當監控的文件內容變化時觸發,此時可重新讀取并解析 JSON從網絡請求獲取 JSON(QNetworkAccessManager)
網絡請求是典型的異步場景,通過信號觸發 JSON 解析:
QNetworkReply::finished()
網絡請求完成時觸發,此時可讀取響應數據并解析
?解析HTTP響應后獲取的JSON文件
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QUrl>
#include <QNetworkReply>
#include <QFile>
#include <QIODevice>
#include <QFileInfo>
#include <QDir>
#include <QTextStream>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);networkAccessManger = new QNetworkAccessManager(this);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_GET_clicked()
{QUrl url("http://127.0.0.1:8080/work/worktask/work.json");QNetworkRequest request(url);//發送GET請求QNetworkReply *reply = networkAccessManger->get(request);//連接響應完成信號connect(reply, &QNetworkReply::finished, this, [=](){if(reply->error() == QNetworkReply::NoError){qDebug() << "success GET";}else{//處理錯誤qDebug() << "Error:" << reply->errorString();}reply->deleteLater(); //釋放資源});connect(reply, &QNetworkReply::readyRead, this, [=](){//處理成功響應---將響應數據寫入data.json文件QFile file("D:/QT/QTproject/networkHTTP/data.json");//打開文件 WriteOnly模式,若文件存在則覆蓋,不存在則創建if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)){qDebug() << "文件打開失敗:" << file.errorString();return;}QByteArray data = reply->readAll();qDebug() << "GETdata:\n" << data;//寫入文件QTextStream out(&file);//設置編碼(避免中文亂碼)out.setEncoding(QStringConverter::Utf8);//寫入內容out << data;//驗證文件是否寫入成功if (file.error() != QFile::NoError){qDebug() << "文件寫入失敗:" << file.errorString();return;}file.flush();file.close();});
}void MainWindow::on_POST_clicked()
{QByteArray data;//數據以json格式傳輸/** json數據格式* {* "username":"xiaowang",* "password":"123456",* }*///QString paramsdata("{\"username\":\"xiaowang\",\"pasword\":\"123456\"}");QString paramsdata("username=xiaowang&pasword=123456");data = paramsdata.toUtf8();QUrl url;url.setScheme("http");url.setHost("127.0.0.1");url.setPort(8080);url.setPath("/work/worktask/work.json");QNetworkRequest request(url);//設置請求頭//json格式request.setRawHeader("content-type","application/json");//表單格式//request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");QNetworkReply *reply = networkAccessManger->post(request,data);//連接完成信號//連接響應完成信號connect(reply, &QNetworkReply::finished, this, [=](){if(reply->error() == QNetworkReply::NoError){qDebug() << "success GET";}else{//處理錯誤qDebug() << "Error:" << reply->errorString();}reply->deleteLater(); //釋放資源});connect(reply, &QNetworkReply::readyRead, this, [=](){//處理成功響應QByteArray data = reply->readAll();qDebug() << "GETdata:\n" << data;});
}void MainWindow::on_GET_JSON_clicked()
{//檢查文件是否存在QFileInfo fileInfo("D:/QT/QTproject/networkHTTP/data.json");if(!fileInfo.exists()){qDebug() << "文件不存在";return;}//打開JSON文件QFile file("D:/QT/QTproject/networkHTTP/data.json");QByteArray data;//打開文件if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "文件打開失敗:" << file.errorString();return;}data = file.readAll();file.close();//創建QJsonDocumentQJsonParseError parseError;QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);//檢查文檔有效性if(parseError.error != QJsonParseError::NoError){qDebug() << "解析錯誤:" << parseError.errorString();return;}//檢查JSON文件對象類型---解析JSON文件/*if(doc.isObject()){QJsonObject JsonObj = doc.object();//解析字符串if(JsonObj.contains("name") && JsonObj["name"].isString()){qDebug() << "名稱:" << JsonObj["name"].toString();}//解析數字if(JsonObj.contains("version") && JsonObj["version"].isDouble()){qDebug() << "版本:" << JsonObj["version"].toDouble();}//解析布爾值if(JsonObj.contains("enabled") && JsonObj["enabled"].isBool()){qDebug() << "是否啟用:" << (JsonObj["enabled"].toBool() ? "是" : "否");}//解析嵌套對象if(JsonObj.contains("config") && JsonObj["config"].isObject()){QJsonObject configObj = JsonObj["config"].toObject();if(configObj.contains("timeout") && configObj["timeout"].isDouble()){qDebug() << "超時設置:" << configObj["timeout"].toInt() << "秒";}}//解析數組if(JsonObj.contains("items") && JsonObj["items"].isArray()){QJsonArray itemsArray = JsonObj["items"].toArray();qDebug() << "數組包含" << itemsArray.size() << "個元素:";for(int i = 0; i < itemsArray.size(); i++){QJsonValue item = itemsArray[i];if(item.isString()){qDebug() << "元素" << i << ":" << item.toString();}}}}//解析JSON數組else if(doc.isArray()){qDebug() << "開始解析JSON數組";QJsonArray JsonArray = doc.array();// 遍歷數組(根據實際JSON結構修改)qDebug() << "數組長度:" << JsonArray.size();for(int i = 0; i < JsonArray.size(); i++){QJsonValue element = JsonArray[i];// 假設數組元素是對象if(element.isObject()){QJsonObject obj = element.toObject();if(obj.contains("id") && obj["id"].isDouble()){qDebug() << "第" << i << "個元素ID:" << obj["id"].toInt();}if(obj.contains("name") && obj["name"].isString()){qDebug() << "第" << i << "個元素名稱:" << obj["name"].toString();}}}}*///根節點是對象,包含 "user" 字段if(doc.isObject()){QJsonObject rootObj = doc.object();// 解析 user 對象if(rootObj.contains("user") && rootObj["user"].isObject()){QJsonObject userObj = rootObj["user"].toObject();// 解析用戶基本信息if(userObj.contains("id") && userObj["id"].isDouble()){qDebug() << "用戶ID:" << userObj["id"].toInt();}if(userObj.contains("name") && userObj["name"].isString()){qDebug() << "用戶姓名:" << userObj["name"].toString();}if(userObj.contains("email") && userObj["email"].isString()){qDebug() << "用戶郵箱:" << userObj["email"].toString();}if(userObj.contains("phone") && userObj["phone"].isString()){qDebug() << "用戶電話:" << userObj["phone"].toString();}// 解析地址(嵌套對象)if(userObj.contains("address") && userObj["address"].isObject()){QJsonObject addressObj = userObj["address"].toObject();qDebug() << "用戶地址:";if(addressObj.contains("street") && addressObj["street"].isString()){qDebug() << " 街道:" << addressObj["street"].toString();}if(addressObj.contains("city") && addressObj["city"].isString()){qDebug() << " 城市:" << addressObj["city"].toString();}if(addressObj.contains("postalCode") && addressObj["postalCode"].isString()){qDebug() << " 郵編:" << addressObj["postalCode"].toString();}if(addressObj.contains("country") && addressObj["country"].isString()){qDebug() << " 國家:" << addressObj["country"].toString();}}// 解析訂單列表(數組)if(userObj.contains("orders") && userObj["orders"].isArray()){QJsonArray ordersArray = userObj["orders"].toArray();qDebug() << "\n訂單總數:" << ordersArray.size();for(int i = 0; i < ordersArray.size(); i++){QJsonValue orderVal = ordersArray[i];if(orderVal.isObject()){QJsonObject orderObj = orderVal.toObject();qDebug() << "\n訂單" << i+1 << ":";if(orderObj.contains("orderId") && orderObj["orderId"].isString()){qDebug() << " 訂單ID:" << orderObj["orderId"].toString();}if(orderObj.contains("orderDate") && orderObj["orderDate"].isString()){qDebug() << " 訂單日期:" << orderObj["orderDate"].toString();}if(orderObj.contains("totalAmount") && orderObj["totalAmount"].isDouble()){qDebug() << " 訂單總金額:" << orderObj["totalAmount"].toDouble() << "元";}// 解析訂單項(數組)if(orderObj.contains("items") && orderObj["items"].isArray()){QJsonArray itemsArray = orderObj["items"].toArray();qDebug() << " 訂單項數量:" << itemsArray.size();for(int j = 0; j < itemsArray.size(); j++){QJsonValue itemVal = itemsArray[j];if(itemVal.isObject()){QJsonObject itemObj = itemVal.toObject();qDebug() << " 商品" << j+1 << ":";if(itemObj.contains("productId") && itemObj["productId"].isString()){qDebug() << " 商品ID:" << itemObj["productId"].toString();}if(itemObj.contains("productName") && itemObj["productName"].isString()){qDebug() << " 商品名稱:" << itemObj["productName"].toString();}if(itemObj.contains("quantity") && itemObj["quantity"].isDouble()){qDebug() << " 數量:" << itemObj["quantity"].toInt();}if(itemObj.contains("price") && itemObj["price"].isDouble()){qDebug() << " 單價:" << itemObj["price"].toDouble() << "元";}}}}}}}}}
}
?其中的解析對象或數組部分需要根據響應的JSON文件編寫
JSON文件
解析后的?
結語:
無論你是初學者還是有經驗的開發者,我希望我的博客能對你的學習之路有所幫助。如果你覺得這篇文章有用,不妨點擊收藏,或者留下你的評論分享你的見解和經驗,也歡迎你對我博客的內容提出建議和問題。每一次的點贊、評論、分享和關注都是對我的最大支持,也是對我持續分享和創作的動力