首页 » Web前端 » phpqt封装技巧_Qt 封装HTTP收集对象类HttpClient

phpqt封装技巧_Qt 封装HTTP收集对象类HttpClient

访客 2024-12-02 0

扫一扫用手机浏览

文章目录 [+]

// [[1]] GET 要求无参数HttpClient("http://localhost:8080/device").success([](const QString &response) {qDebug() << response;}).get();

更多的利用方法请参考 main() 里的例子。
HttpClient 的实现为 HttpClient.h 和 HttpClient.cpp 部分。

二、main.cpp

main() 函数里展示了 HttpClient 的利用示例。

phpqt封装技巧_Qt 封装HTTP收集对象类HttpClient

#include <QApplication>#include <QNetworkAccessManager>#include <QDebug>#include <QFile>#include "HttpClient.h"int main(int argc, char argv[]) {QApplication a(argc, argv);// 在代码块里实行网络访问,是为了测试 HttpClient 工具在被析构后,网络访问的回调函数仍旧能正常实行{ // [[1]] GET 要求无参数 HttpClient("http://localhost:8080/device").success([](const QString &response) { qDebug() << response; }).get(); // [[2]] GET 要求有参数,有自定义 header HttpClient("http://localhost:8080/device").success([](const QString &response) { qDebug() << response; }).param("id", "1").param("name", "诸葛亮").header("token", "123AS#D").get(); // [[3]] POST 要求有参数,有自定义 header HttpClient("http://localhost:8080/device").success([](const QString &response) { qDebug() << response; }).param("id", "2").param("name", "卧龙").header("token", "DER#2J7") .header("content-type", "application/x-www-form-urlencoded").post(); // [[4]] 每创建一个 QNetworkAccessManager 工具都会创建一个线程,当频繁的访问网络时,为了节省线程资源,调用 useManager() // 利用共享的 QNetworkAccessManager,它不会被 HttpClient 删除。
// 如果下面的代码不传入 QNetworkAccessManager,从任务管理器里可以看到创建了几千个线程。
QNetworkAccessManager manager = new QNetworkAccessManager(); for (int i = 0; i < 5000; ++i) { HttpClient("http://localhost:8080/device").success([=](const QString &response) { qDebug() << response << ", " << i; }).manager(manager).get(); }} return a.exec();}
三、HttpClient.h

#ifndef HTTPCLIENT_H#define HTTPCLIENT_H#include <functional>#include <QMap>#include <QVariant>#include <QStringList>#include <QNetworkReply>#include <QNetworkRequest>#include <QNetworkAccessManager>class HttpClientPrivate;/ 对 QNetworkAccessManager 大略封装的 HTTP 访问客户端,简化 GET、POST、PUT、DELETE、上传、下载等操作。
在实行要求前设置须要的参数和回调函数: 1. 调用 header() 设置要求头 2. 调用 param() 设置参数,利用 Form 表单的办法提交要求,GET 要求的 query parameters 也可以用它设置 3. 调用 json() 设置 JSON 字符串的 request body,Content-Type 为 application/json, 当然也可以不是 JSON 格式,因利用 request body 的情形多数是利用 JSON 格式通报繁芜工具,故命名为 json 4. 调用 success() 注册要求成功的回调函数 5. 调用 fail() 注册要求失落败的回调函数 6. 调用 complete() 注册要求结束的回调函数 success(), fail(), complete() 的回调函数是可选的,根据须要注册对应的回调函数,也可以一个都不注册 然后根据要求的类型调用 get(), post(), put(), remove(), download(), upload() 实行 HTTP 要求 默认 HttpClient 会创建一个 QNetworkAccessManager,如果不想利用默认的,调用 manager() 传入即可。
调用 debug(true) 设置为调试模式,输出调试信息如 URL、参数等。
/class HttpClient {public: HttpClient(const QString &url); ~HttpClient(); void stop2(); / @brief 每创建一个 QNetworkAccessManager 工具都会创建一个线程,当频繁的访问网络时,为了节省线程资源, 可以传入 QNetworkAccessManager 给多个要求共享 (它不会被 HttpClient 删除,用户须要自己手动删除)。
如果没有利用 manager() 传入一个 QNetworkAccessManager,则 HttpClient 会自动的创建一个,并且在网络访问完成后自动删除它。
@param manager 实行 HTTP 要求的 QNetworkAccessManager 工具 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& manager(QNetworkAccessManager manager); / @brief 参数 debug 为 true 则利用 debug 模式,要求实行时输出要求的 URL 和参数等 @param debug 是否启用调试模式 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& debug(bool debug); / @brief 添加一个要求的参数,可以多次调用添加多个参数 @param name 参数的名字 @param value 参数的值 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& param(const QString &name, const QVariant &value); / @brief 添加多个要求的参数 @param ps QMap 类型的参数,key 为参数名,value 为参数值 可以利用 {{"name", 1}, {"box", 2}} 的办法创建 QMap 工具 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& params(const QMap<QString, QVariant> &ps); / @brief 添加要求的参数 (要求体),利用 Json 格式,例如 "{\"name\": \"Alice\"}" @param json 要求体 (request body) 为 Json 格式的参数字符串 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& json(const QString &json); / @brief 添加要求头 @param name 要求头的名字 @param value 要求头的值 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& header(const QString &name, const QString &value); / @brief 添加多个要求头 @param nameValues 要求头的名字和值对 可以利用 {{"name", 1}, {"box", 2}} 的办法创建 QMap 工具 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& headers(const QMap<QString, QString> nameValues); / @brief 注册要求成功的回调函数 @param successHandler 成功的回调函数,参数为相应的字符串 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& success(std::function<void(const QString &)> successHandler); / @brief 注册要求失落败的回调函数 @param failHandler 失落败的回调函数,参数为失落败缘故原由和 HTTP 状态码 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& fail(std::function<void(const QString &, int)> failHandler); / @brief 注册要求结束的回调函数,不管成功还是失落败要求结束后都会实行 @param completeHandler 完成的回调函数,无参数 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& complete(std::function<void()> completeHandler); / @brief 设置要求相应的字符集,默认利用 UTF-8 @param cs 字符集 @return 返回 HttpClient 的引用,可以用于链式调用 / HttpClient& charset(const QString &cs); / @brief 实行 GET 要求 / void get(); / @brief 实行 POST 要求 / void post(); / @brief 实行 PUT 要求 / void put(); / @brief 实行 DELETE 要求,由于 delete 是 C++ 的运算符,以是用同义词 remove 把稳: Qt 供应的 DELETE 要求是不支持通报参数的, 请参考 QNetworkAccessManager::deleteResource(const QNetworkRequest &request) / void remove(); / @brief 利用 GET 进行下载,下载的文件保存到 savePath @param savePath 下载的文件保存路径 / void download(const QString &savePath); / @brief 上传单个文件 利用 POST 上传,做事器端获取文件的参数名为 file @param path 要上传的文件的路径 / void upload(const QString &path); / @brief 上传文件,文件的内容已经读取到 data 中 利用 POST 上传,做事器端获取文件的参数名为 file @param path 要上传的文件的路径 / void upload(const QByteArray &data); / @brief 上传多个文件 利用 POST 上传,做事器端获取文件的参数名为 files @param paths 要上传的文件的路径 / void upload(const QStringList &paths);private: HttpClientPrivate d;};#endif // HTTPCLIENT_H
四、HttpClient.cpp

#include "HttpClient.h"#include <QDebug>#include <QFile>#include <QHash>#include <QUrlQuery>#include <QHttpPart>#include <QHttpMultiPart>/-----------------------------------------------------------------------------|| HttpClientPrivate ||----------------------------------------------------------------------------// @brief 要求的类型 注: UPLOAD 不是 HTTP Method,只是为了上传时对要求进行分外处理而定义的/enum class HttpClientRequestMethod { GET, POST, PUT, DELETE, UPLOAD};/ @brief 缓存 HttpClientPrivate 的数据成员,方便在异步 lambda 中利用 = 以值的办法访问。
/class HttpClientPrivateCache {public: std::function<void(const QString &)> successHandler = nullptr; std::function<void(const QString &, int)> failHandler = nullptr; std::function<void()> completeHandler = nullptr; bool debug = false; bool internal = false; QString charset; QNetworkAccessManager manager = nullptr;};/ @brief HttpClient 的赞助类,封装不肯望暴露给客户真个数据和方法,使得 HttpClient 只暴露必要的 API 给客户端。
/class HttpClientPrivate { friend class HttpClient; HttpClientPrivate(const QString &url); ~HttpClientPrivate(); void stop1(); / @brief 缓存 HttpClientPrivate 的数据成员 @return 返回 HttpClientPrivateCache 缓存工具 / HttpClientPrivateCache cache(); / @brief 获取 Manager,如果传入了 manager 则返回此 manager,否则新创建一个 manager,默认会自动创建一个 manager, 利用传入的 manager 则 interval 被设置为 false,自动创建的 manager 则设置 interval 为 true @return 返回 QNetworkAccessManager 工具 / QNetworkAccessManager getManager(); / @brief 利用用户设定的 URL、要求头、参数等创建 Request @param d HttpClientPrivate 的工具 @param method 要求的类型 @return 返回可用于实行要求的 QNetworkRequest / static QNetworkRequest createRequest(HttpClientPrivate d, HttpClientRequestMethod method); / @brief 实行要求的赞助函数 @param d HttpClientPrivate 的工具 @param method 要求的类型 / static void executeQuery(HttpClientPrivate d, HttpClientRequestMethod method); / @brief 上传文件或者数据 @param d HttpClientPrivate 的工具 @param paths 要上传的文件的路径(path 和 data 不能同时利用) @param data 要上传的文件的数据 / static void upload(HttpClientPrivate d, const QStringList &paths, const QByteArray &data); / @brief 利用 GET 进行下载,下载的文件保存到 savePath @param d HttpClientPrivate 的工具 @param savePath 下载的文件保存路径 / static void download(HttpClientPrivate d, const QString &savePath); / @brief 利用 GET 进行下载,当有数据可读取时回调 readyRead(), 大多数情形下该当在 readyRead() 里把数据保存到文件 @param readyRead 有数据可读取时的回调 lambda 函数 / static void download(HttpClientPrivate d, std::function<void(const QByteArray &)> readyRead); / @brief 读取做事器相应的数据 @param reply 要求的 QNetworkReply 工具 @param charset 要求相应的字符集,默认利用 UTF-8 @return 返回做事器端相应的字符串 / static QString readReply(QNetworkReply reply, const QString &charset = "UTF-8"); / @brief 要求结束的处理函数 @param cache HttpClientPrivateCache 缓存工具 @param reply QNetworkReply 工具,不能为 NULL @param successMessage 要求成功的 @param failMessage 要求失落败的 / static void handleFinish(HttpClientPrivateCache cache, QNetworkReply reply, const QString &successMessage, const QString &failMessage); /////////////////////////////////////////////////// 成员变量 ////////////////////////////////////////////// QString url; // 要求的 URL QString json; // 要求的参数利用 Json 格式 QUrlQuery params; // 要求的参数利用 Form 格式 QString charset = "UTF-8"; // 要求相应的字符集 QHash<QString, QString> headers; // 要求头 QNetworkAccessManager manager = nullptr; // 实行 HTTP 要求的 QNetworkAccessManager 工具 bool useJson = false; // 为 true 时要求利用 Json 格式通报参数,否则利用 Form 格式通报参数 bool debug = false; // 为 true 时输出要求的 URL 和参数 bool internal = true; // 是否利用自动创建的 manager std::function<void(const QString &)> successHandler = nullptr; // 成功的回调函数,参数为相应的字符串 std::function<void(const QString &, int)> failHandler = nullptr; // 失落败的回调函数,参数为失落败缘故原由和 HTTP status code std::function<void()> completeHandler = nullptr; // 结束的回调函数,无参数};HttpClientPrivate::HttpClientPrivate(const QString &url) : url(url) { }HttpClientPrivate::~HttpClientPrivate() { manager = nullptr; successHandler = nullptr; failHandler = nullptr; completeHandler = nullptr;}void HttpClientPrivate::stop1(){ manager->deleteLater();}// 缓存 HttpClientPrivate 的数据成员HttpClientPrivateCache HttpClientPrivate::cache() { HttpClientPrivateCache cache; cache.successHandler = successHandler; cache.failHandler = failHandler; cache.completeHandler = completeHandler; cache.debug = debug; cache.internal = internal; cache.charset = charset; cache.manager = getManager(); return cache;}// 实行要求的赞助函数void HttpClientPrivate::executeQuery(HttpClientPrivate d, HttpClientRequestMethod method) { // 1. 缓存须要的变量,在 lambda 中利用 = 捕获进行值通报 (不能利用引用 &,由于 d 已经被析构) // 2. 创建要求须要的变量 // 3. 根据 method 实行不同的要求 // 4. 要求结束时获取相应数据,在 handleFinish 中实行回调函数 // [1] 缓存须要的变量,在 lambda 中利用 = 捕获进行值通报 (不能利用引用 &,由于 d 已经被析构) HttpClientPrivateCache cache = d->cache(); // [2] 创建要求须要的变量 QNetworkRequest request = HttpClientPrivate::createRequest(d, method); QNetworkReply reply = nullptr; // [3] 根据 method 实行不同的要求 switch (method) { case HttpClientRequestMethod::GET: reply = cache.manager->get(request); break; case HttpClientRequestMethod::POST: reply = cache.manager->post(request, d->useJson ? d->json.toUtf8() : d->params.toString(QUrl::FullyEncoded).toUtf8()); break; case HttpClientRequestMethod::PUT: reply = cache.manager->put(request, d->useJson ? d->json.toUtf8() : d->params.toString(QUrl::FullyEncoded).toUtf8()); break; case HttpClientRequestMethod::DELETE: reply = cache.manager->deleteResource(request); break; default: break; } // [4] 要求结束时获取相应数据,在 handleFinish 中实行回调函数 // 要求结束时一次性读取所有相应数据 QObject::connect(reply, &QNetworkReply::finished, [=] { QString successMessage = HttpClientPrivate::readReply(reply, cache.charset.toUtf8()); QString failMessage = reply->errorString(); HttpClientPrivate::handleFinish(cache, reply, successMessage, failMessage); });}// 利用 GET 进行下载,下载的文件保存到 savePathvoid HttpClientPrivate::download(HttpClientPrivate d, const QString &savePath) { // 1. 打开下载文件,如果打开文件出错,不进行下载 // 2. 给要求结束的回调函数注入关闭开释文件的行为 // 3. 调用下载的重载函数开始下载 QFile file = new QFile(savePath); // [1] 打开下载文件,如果打开文件出错,不进行下载 if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) { file->close(); file->deleteLater(); if (d->debug) { qDebug().noquote() << QString("[缺点] 打开文件出错: %1").arg(savePath); } if (nullptr != d->failHandler) { d->failHandler(QString("[缺点] 打开文件出错: %1").arg(savePath), -1); } return; } // [2] 给要求结束的回调函数注入关闭开释文件的行为 std::function<void()> userCompleteHandler = d->completeHandler; std::function<void()> injectedCompleteHandler = [=]() { // 要求结束后开释文件工具 file->flush(); file->close(); file->deleteLater(); // 实行用户指定的结束回调函数 if (nullptr != userCompleteHandler) { userCompleteHandler(); } }; d->completeHandler = injectedCompleteHandler; // [3] 调用下载的重载函数开始下载 HttpClientPrivate::download(d, [=](const QByteArray &data) { file->write(data); });}// 利用 GET 进行下载,当有数据可读取时回调 readyRead(), 大多数情形下该当在 readyRead() 里把数据保存到文件void HttpClientPrivate::download(HttpClientPrivate d, std::function<void(const QByteArray &)> readyRead) { // 1. 缓存须要的变量,在 lambda 中利用 = 捕获进行值通报 (不能利用引用 &,由于 d 已经被析构) // 2. 创建要求须要的变量,实行要求 // 3. 有数据可读取时回调 readyRead() // 4. 要求结束时获取相应数据,在 handleFinish 中实行回调函数 // [1] 缓存须要的变量,在 lambda 中利用 = 捕捉利用 (不能利用引用 &,由于 d 已经被析构) HttpClientPrivateCache cache = d->cache(); // [2] 创建要求须要的变量,实行要求 QNetworkRequest request = HttpClientPrivate::createRequest(d, HttpClientRequestMethod::GET); QNetworkReply reply = cache.manager->get(request); // [3] 有数据可读取时回调 readyRead() QObject::connect(reply, &QNetworkReply::readyRead, [=] { readyRead(reply->readAll()); }); // [4] 要求结束时获取相应数据,在 handleFinish 中实行回调函数 QObject::connect(reply, &QNetworkReply::finished, [=] { QString successMessage = "下载完成"; // 要求结束时一次性读取所有相应数据 QString failMessage = reply->errorString(); HttpClientPrivate::handleFinish(cache, reply, successMessage, failMessage); });}// 上传文件或者数据的实现void HttpClientPrivate::upload(HttpClientPrivate d, const QStringList &paths, const QByteArray &data) { // 1. 缓存须要的变量,在 lambda 中利用 = 捕获进行值通报 (不能利用引用 &,由于 d 已经被析构) // 2. 创建 Form 表单的参数 Text Part // 3. 创建上传的 File Part // 3.1 利用文件创建 File Part // 3.2 利用数据创建 File Part // 4. 创建要求须要的变量,实行要求 // 5. 要求结束时开释 multiPart 和打开的文件,获取相应数据,在 handleFinish 中实行回调函数 // [1] 缓存须要的变量,在 lambda 中利用 = 捕捉利用 (不能利用引用 &,由于 d 已经被析构) HttpClientPrivateCache cache = d->cache(); // [2] 创建 Form 表单的参数 Text Part QHttpMultiPart multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QList<QPair<QString, QString> > paramItems = d->params.queryItems(); for (int i = 0; i < paramItems.size(); ++i) { QString name = paramItems.at(i).first; QString value = paramItems.at(i).second; QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(name)); textPart.setBody(value.toUtf8()); multiPart->append(textPart); } if (paths.size() > 0) { // [3.1] 利用文件创建 File Part QString inputName = paths.size() == 1 ? "file" : "files"; // 一个文件时为 file,多个文件时为 files for (const QString &path : paths) { // path 为空时,不上传文件 if (path.isEmpty()) { continue; } // We cannot delete the file now, so delete it with the multiPart QFile file = new QFile(path, multiPart); // 如果文件打开失落败,则开释资源返回,终止上传 if (!file->open(QIODevice::ReadOnly)) { QString failMessage = QString("打开文件失落败[%2]: %1").arg(path).arg(file->errorString()); if (cache.debug) { qDebug().noquote() << failMessage; } if (nullptr != cache.failHandler) { cache.failHandler(failMessage, -1); } multiPart->deleteLater(); return; } // 单个文件时,name 为做事器端获取文件的参数名,为 file // 多个文件时,name 为做事器端获取文件的参数名,为 files // 把稳: 做事器是 Java 的则用 form-data // 把稳: 做事器是 PHP 的则用 multipart/form-data QString disposition = QString("form-data; name=\"%1\"; filename=\"%2\"").arg(inputName).arg(file->fileName()); QHttpPart filePart; filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(disposition)); filePart.setBodyDevice(file); multiPart->append(filePart); } } else { // [3.2] 利用数据创建 File Part QString disposition = QString("form-data; name=\"file\"; filename=\"no-name\""); QHttpPart dataPart; dataPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(disposition)); dataPart.setBody(data); multiPart->append(dataPart); } // [4] 创建要求须要的变量,实行要求 QNetworkRequest request = HttpClientPrivate::createRequest(d, HttpClientRequestMethod::UPLOAD); QNetworkReply reply = cache.manager->post(request, multiPart); // [5] 要求结束时开释 multiPart 和文件,获取相应数据,在 handleFinish 中实行回调函数 QObject::connect(reply, &QNetworkReply::finished, [=] { multiPart->deleteLater(); // 开释资源: multiPart + file QString successMessage = HttpClientPrivate::readReply(reply, cache.charset); // 要求结束时一次性读取所有相应数据 QString failMessage = reply->errorString(); HttpClientPrivate::handleFinish(cache, reply, successMessage, failMessage); });}// 获取 Manager,如果传入了 manager 则返回此 manager,否则新创建一个 manager,默认会自动创建一个 managerQNetworkAccessManager HttpClientPrivate::getManager() { return internal ? new QNetworkAccessManager() : manager;}// 利用用户设定的 URL、要求头、参数等创建 RequestQNetworkRequest HttpClientPrivate::createRequest(HttpClientPrivate d, HttpClientRequestMethod method) { // 1. 如果是 GET 要求,并且参数不为空,则编码要求的参数,放到 URL 后面 // 2. 调试时输出网址和参数 // 3. 设置 Content-Type // 4. 添加要求头到 request 中 bool get = method == HttpClientRequestMethod::GET; bool upload = method == HttpClientRequestMethod::UPLOAD; bool withForm = !get && !upload && !d->useJson; // PUT、POST 或者 DELETE 要求,且 useJson 为 false bool withJson = !get && !upload && d->useJson; // PUT、POST 或者 DELETE 要求,且 useJson 为 true // [1] 如果是 GET 要求,并且参数不为空,则编码要求的参数,放到 URL 后面 if (get && !d->params.isEmpty()) { d->url += "?" + d->params.toString(QUrl::FullyEncoded); } // [2] 调试时输出网址和参数 if (d->debug) { qDebug().noquote() << "[网址]" << d->url; if (withJson) { qDebug().noquote() << "[参数]" << d->json; } else if (withForm || upload) { QList<QPair<QString, QString> > paramItems = d->params.queryItems(); QString buffer; // 避免多次调用 qDebug() 输入调试信息,每次 qDebug() 都有可能输出行号等 // 按键值对的办法输出参数 for (int i = 0; i < paramItems.size(); ++i) { QString name = paramItems.at(i).first; QString value = paramItems.at(i).second; if (0 == i) { buffer += QString("[参数] %1=%2\n").arg(name).arg(value); } else { buffer += QString(" %1=%2\n").arg(name).arg(value); } } if (!buffer.isEmpty()) { qDebug().noquote() << buffer; } } } // [3] 设置 Content-Type // 如果是 POST 要求,useJson 为 true 时添加 Json 的要求头,useJson 为 false 时添加 Form 的要求头 if (withForm) { d->headers["Content-Type"] = "application/x-www-form-urlencoded"; } else if (withJson) { d->headers["Content-Type"] = "application/json; charset=utf-8"; } // [4] 添加要求头到 request 中 QNetworkRequest request(QUrl(d->url)); for (auto i = d->headers.cbegin(); i != d->headers.cend(); ++i) { request.setRawHeader(i.key().toUtf8(), i.value().toUtf8()); } return request;}// 读取做事器相应的数据QString HttpClientPrivate::readReply(QNetworkReply reply, const QString &charset) { QTextStream in(reply); QString result; in.setCodec(charset.toUtf8()); while (!in.atEnd()) { result += in.readLine(); } return result;}// 要求结束的处理函数void HttpClientPrivate::handleFinish(HttpClientPrivateCache cache, QNetworkReply reply, const QString &successMessage, const QString &failMessage) { // 1. 实行要求成功的回调函数 // 2. 实行要求失落败的回调函数 // 3. 实行要求结束的回调函数 // 4. 开释 reply 和 manager 工具 if (reply->error() == QNetworkReply::NoError) { if (cache.debug) { qDebug().noquote() << QString("[结束] 成功: %1").arg(successMessage); } // [1] 实行要求成功的回调函数 if (nullptr != cache.successHandler) { cache.successHandler(successMessage); } } else { if (cache.debug) { qDebug().noquote() << QString("[结束] 失落败: %1").arg(failMessage); } // [2] 实行要求失落败的回调函数 if (nullptr != cache.failHandler) { cache.failHandler(failMessage, reply->error()); } } // [3] 实行要求结束的回调函数 if (nullptr != cache.completeHandler) { cache.completeHandler(); } // [4] 开释 reply 和 manager 工具 if (nullptr != reply) { reply->deleteLater(); } if (cache.internal && nullptr != cache.manager) { cache.manager->deleteLater(); }}/-----------------------------------------------------------------------------|| HttpClient ||----------------------------------------------------------------------------/// 把稳: 在异步要求中 HttpClient 的 HttpClientPrivate 成员变量 d 已经被析构,以是须要先缓存干系变量为栈工具,利用 = 以值的办法访问HttpClient::HttpClient(const QString &url) : d(new HttpClientPrivate(url)) { }HttpClient::~HttpClient() { delete d;}void HttpClient::stop2(){ d->stop1();}// 传入 QNetworkAccessManager 给多个要求共享HttpClient& HttpClient::manager(QNetworkAccessManager manager) { d->manager = manager; d->internal = (nullptr == manager); return this;}// 传入 debug 为 true 则利用 debug 模式,要求实行时输出要求的 URL 和参数等HttpClient& HttpClient::debug(bool debug) { d->debug = debug; return this;}// 添加一个要求的参数,可以多次调用添加多个参数HttpClient& HttpClient::param(const QString &name, const QVariant &value) { d->params.addQueryItem(name, value.toString()); return this;}// 添加多个要求的参数HttpClient& HttpClient::params(const QMap<QString, QVariant> &ps) { for (auto iter = ps.cbegin(); iter != ps.cend(); ++iter) { d->params.addQueryItem(iter.key(), iter.value().toString()); } return this;}// 添加要求的参数 (要求体),利用 Json 格式,例如 "{\"name\": \"Alice\"}"HttpClient& HttpClient::json(const QString &json) { d->json = json; d->useJson = true; return this;}// 添加要求头HttpClient& HttpClient::header(const QString &name, const QString &value) { d->headers[name] = value; return this;}// 添加多个要求头HttpClient& HttpClient::headers(const QMap<QString, QString> nameValues) { for (auto i = nameValues.cbegin(); i != nameValues.cend(); ++i) { d->headers[i.key()] = i.value(); } return this;}// 注册要求成功的回调函数HttpClient& HttpClient::success(std::function<void(const QString &)> successHandler) { d->successHandler = successHandler; return this;}// 注册要求失落败的回调函数HttpClient& HttpClient::fail(std::function<void(const QString &, int)> failHandler) { d->failHandler = failHandler; return this;}// 注册要求结束的回调函数,不管成功还是失落败都会实行HttpClient& HttpClient::complete(std::function<void()> completeHandler) { d->completeHandler = completeHandler; return this;}// 设置要求相应的编码HttpClient& HttpClient::charset(const QString &cs) { d->charset = cs; return this;}// 实行 GET 要求void HttpClient::get() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::GET);}// 实行 POST 要求void HttpClient::post() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::POST);}// 实行 PUT 要求void HttpClient::put() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::PUT);}// 实行 DELETE 要求void HttpClient::remove() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::DELETE);}// 利用 GET 进行下载,下载的文件保存到 savePathvoid HttpClient::download(const QString &savePath) { HttpClientPrivate::download(d, savePath);}// 上传文件void HttpClient::upload(const QString &path) { QStringList paths = { path }; HttpClientPrivate::upload(d, paths, QByteArray());}// 上传文件,文件的内容以及读取到 data 中void HttpClient::upload(const QByteArray &data) { HttpClientPrivate::upload(d, QStringList(), data);}// 上传多个文件void HttpClient::upload(const QStringList &paths) { HttpClientPrivate::upload(d, paths, QByteArray());}

参考:

phpqt封装技巧_Qt 封装HTTP收集对象类HttpClient
(图片来自网络侵删)

Qt 访问网络的 HttpClient

Qt 访问网络的 HttpClient(封装QNetworkAccessManager,且有做事端)

点击领取Qt学习资料+视频教程~Qt开拓(视频教程+文档+代码+项目实战)

相关文章

介绍百度码,技术革新背后的智慧之光

随着科技的飞速发展,互联网技术已经成为我们生活中不可或缺的一部分。而在这个信息爆炸的时代,如何快速、准确地获取信息,成为了人们关注...

Web前端 2025-01-03 阅读1 评论0

介绍皮箱密码,开启神秘之门的钥匙

皮箱,作为日常生活中常见的收纳工具,承载着我们的珍贵物品。面对紧闭的皮箱,许多人却束手无策。如何才能轻松打开皮箱呢?本文将为您揭秘...

Web前端 2025-01-03 阅读1 评论0

介绍盗号器,网络安全的隐忧与应对步骤

随着互联网的快速发展,网络安全问题日益突出。盗号器作为一种非法工具,对网民的个人信息安全构成了严重威胁。本文将深入剖析盗号器的原理...

Web前端 2025-01-03 阅读1 评论0