当前位置: 首页 > news >正文

QT开发---网络编程下

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/jsonapplication/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/htmlapplication/json等)。

    • Content-Length:指定响应体的长度(以字节为单位)。

    • Set-Cookie:用于设置Cookie,将状态信息发送到客户端。

    • Location:用于重定向,指定新的资源位置。

  • 空行:表示请求头部的结束。

  • 响应体包含服务器返回给客户端的资源内容,如网页HTML代码、图片数据等。

URL(统一资源定位符)

  • URI:统一资源标识符,用于唯一标识资源,是一个更广泛的术语。

  • URL:统一资源定位符,是URI的一个子集,用于标识资源的具体位置,可以直接用于访问资源

  • 结构   scheme://authority/path[?query][#fragment]

    • fragment:片段标识符,通常用于标识资源内部的某个部分。

    • query:查询参数,用于向服务器传递额外的信息。

    • path:资源的路径,通常是一个层次化的路径结构。

    • authority:资源所在的主机名或IP地址,可选地包括端口号。

    • scheme:协议类型,如httphttpsftp等。

    • 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)可以是以下类型之一:

      • 字符串(用双引号括起来)

      • 数字(整数或浮点数)

      • 布尔值(truefalse

      • 数组(用方括号[]括起来)

      • 对象(用大括号{}括起来)

      • 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文件

解析后的 

结语:

无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力

http://www.lryc.cn/news/601340.html

相关文章:

  • 全面理解JVM虚拟机
  • Python day26
  • Python数据分析基础(一)
  • 沪深L2逐笔十档委托队列分时Tick历史数据分析处理
  • RK3568 Linux驱动学习——U-Boot使用
  • 15.7 DeepSpeed实战:单卡38GB到多卡12GB,3倍效率提升的ZeRO-3配置全解
  • golang设置http代理
  • 2025年Solar应急响应公益月赛-7月wp
  • 将 JsonArray 类型的数据导出到Excel文件里的两种方式
  • 新手向:IDM下载失败排查
  • keepalived入门及其基础运用实验
  • Java面试宝典:MySQL执行原理二
  • 字节跳动Coze Studio开源了!架构解析
  • 数据处理实战(含代码)
  • Web Worker:解锁浏览器多线程,提升前端性能与体验
  • 数据结构基础内容(第十篇:排序)
  • 力扣129. 求根节点到叶节点数字之和
  • 力扣热题100----------53最大子数组和
  • 【多模态】天池AFAC赛道四-智能体赋能的金融多模态报告自动化生成part2-报告输出
  • logstash采集springboot微服务日志
  • Spring经典“送命题”:BeanFactory vs FactoryBean
  • 力扣131:分割回文串
  • JavaScript单线程实现异步
  • 探秘CommonJS:Node.js模块化核心解析
  • GPT-4o实战应用指南:从入门到精通的技术心得
  • 物联网安装调试-物联网网关
  • 【图像处理基石】Segment Anything Model (SAM) 调研
  • MGRE综合实验
  • 望言OCR视频字幕提取2025终极评测:免费版VS专业版提全方位对比(含免费下载)
  • 20250707-2-Kubernetes 网络-Ingress暴露应用(http与https)_笔记