Qt之http客户端类

  一、HTTP客户端类功能:

1、POST请求发送:

  • 支持发送JSON格式的数据
  • 自动处理请求头设置
  • 提供上传进度监控、

2、GET请求发送:

  • 简单的GET请求实现
  • 支持下载进度监控

3、状态监控:

  • 通过信号槽机制监控上传/下载进度
  • 错误处理和状态回调
/**
 * @file HttpClient.h
 * @brief HTTP客户端类,用于处理HTTP请求
 * @details 提供异步HTTP请求功能,支持GET和POST方法,包含进度监控和错误处理
 */

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QEventLoop>

/**
 * @class HttpClient
 * @brief HTTP客户端类,继承自QObject
 * @details 封装了Qt网络请求功能,提供简单的接口进行HTTP通信
 */
class HttpClient : public QObject 
{
    Q_OBJECT

public:
    /**
     * @brief 构造函数
     * @param parent 父对象指针,用于Qt对象树管理
     */
    explicit HttpClient(QObject *parent = nullptr) : QObject(parent) {
        manager = new QNetworkAccessManager(this);
    }

    /**
     * @brief 析构函数
     * @details 清理网络管理器资源
     */
    ~HttpClient() {
        if (manager) {
            manager->deleteLater();
            manager = nullptr;
        }
    }

    /**
     * @brief 发送POST请求
     * @param url 目标URL地址
     * @param data 要发送的JSON数据
     * @param callback 请求完成后的回调函数,参数为(是否成功, 响应内容/错误信息)
     */
    void sendPostRequest(const QString& url, const QJsonObject& data, 
                        std::function<void(bool success, const QString& response)> callback) {
        // 创建网络请求对象
        QNetworkRequest request(url);
        // 设置请求头为JSON格式
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        // 将JSON对象转换为字节数组
        QJsonDocument doc(data);
        QByteArray postData = doc.toJson();

        // 发送POST请求
        QNetworkReply* reply = manager->post(request, postData);

        // 连接完成信号到响应处理函数
        connect(reply, &QNetworkReply::finished, this, [=]() {
            handleResponse(reply, callback);
        });

        // 连接上传进度信号
        connect(reply, &QNetworkReply::uploadProgress, this, 
                &HttpClient::onUploadProgress);

        // 连接下载进度信号
        connect(reply, &QNetworkReply::downloadProgress, this,
                &HttpClient::onDownloadProgress);
    }

    /**
     * @brief 发送GET请求
     * @param url 目标URL地址
     * @param callback 请求完成后的回调函数,参数为(是否成功, 响应内容/错误信息)
     */
    void sendGetRequest(const QString& url,
                       std::function<void(bool success, const QString& response)> callback) {
        QNetworkRequest request(url);
        QNetworkReply* reply = manager->get(request);

        connect(reply, &QNetworkReply::finished, this, [=]() {
            handleResponse(reply, callback);
        });
    }

signals:
    /**
     * @brief 上传进度信号
     * @param bytesSent 已发送的字节数
     * @param bytesTotal 总字节数
     */
    void uploadProgressChanged(qint64 bytesSent, qint64 bytesTotal);

    /**
     * @brief 下载进度信号
     * @param bytesReceived 已接收的字节数
     * @param bytesTotal 总字节数
     */
    void downloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal);

private slots:
    /**
     * @brief 处理上传进度的槽函数
     * @param bytesSent 已发送的字节数
     * @param bytesTotal 总字节数
     */
    void onUploadProgress(qint64 bytesSent, qint64 bytesTotal) {
        emit uploadProgressChanged(bytesSent, bytesTotal);
    }

    /**
     * @brief 处理下载进度的槽函数
     * @param bytesReceived 已接收的字节数
     * @param bytesTotal 总字节数
     */
    void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
        emit downloadProgressChanged(bytesReceived, bytesTotal);
    }

private:
    /** @brief 网络访问管理器指针 */
    QNetworkAccessManager* manager;

    /**
     * @brief 处理网络响应
     * @param reply 网络响应对象指针
     * @param callback 回调函数
     * @details 处理请求完成后的响应数据或错误信息,并调用回调函数
     */
    void handleResponse(QNetworkReply* reply,
                       std::function<void(bool success, const QString& response)> callback) {
        if (reply->error() == QNetworkReply::NoError) {
            // 请求成功,读取响应数据
            QString response = QString::fromUtf8(reply->readAll());
            callback(true, response);
        } else {
            // 请求失败,获取错误信息
            QString errorString = reply->errorString();
            callback(false, errorString);
        }

        // 清理响应对象
        reply->deleteLater();
    }
};

二、使用方式

1、作为类成员变量使用

class MyClass : public QObject {
    Q_OBJECT
private:
    HttpClient* httpClient;

public:
    MyClass(QObject* parent = nullptr) : QObject(parent) {
        httpClient = new HttpClient(this);  // 将this作为父对象
    }
    
    // 不需要显式删除,会随父对象自动删除
    ~MyClass() {
        // httpClient会自动删除,不需要手动删除
    }
};

2、 作为局部变量使用

void someFunction() {
    // 在栈上创建
    HttpClient client;
    
    // 使用client发送请求
    client.sendPostRequest("...", data, [](bool success, const QString& response) {
        // 处理响应
    });
    
    // client会在函数结束时自动销毁
}

3、动态分配使用

void someFunction() {
    // 动态创建
    HttpClient* client = new HttpClient();
    
    // 使用client发送请求
    client->sendPostRequest("...", data, [client](bool success, const QString& response) {
        // 处理响应
        
        // 在回调中删除client
        client->deleteLater();
    });
}

4、使用智能指针

#include <QScopedPointer>

void someFunction() {
    QScopedPointer<HttpClient> client(new HttpClient());
    
    // 使用client发送请求
    client->sendPostRequest("...", data, [](bool success, const QString& response) {
        // 处理响应
    });
    
    // client会在QScopedPointer销毁时自动删除
}

 三、示例

// 创建客户端实例
HttpClient* client = new HttpClient(this);

// 监听进度信号
connect(client, &HttpClient::uploadProgressChanged, this, [](qint64 sent, qint64 total) {
    qDebug() << "Upload progress:" << sent << "/" << total;
});

// 准备POST数据
QJsonObject data;
data["name"] = "test";
data["value"] = 123;

// 发送POST请求
client->sendPostRequest("http://api.example.com/endpoint", data, 
    [](bool success, const QString& response) {
        if (success) {
            qDebug() << "Response:" << response;
        } else {
            qDebug() << "Error:" << response;
        }
    }
);

 

注意事项:

  1. 如果 HttpClient 作为 QObject 的子对象创建,会随父对象自动删除,不需要手动删除
  2. 使用 deleteLater() 而不是直接 delete,确保在 Qt 事件循环中安全删除对象
  3. 如果有正在进行的网络请求,建议等待请求完成后再删除 HttpClient
  4. 使用智能指针可以避免手动管理内存,推荐使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953536.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python】OpenCV—Local Translation Warps

文章目录 1、功能描述2、原理分析3、代码实现4、效果展示5、完整代码6、参考 1、功能描述 利用液化效果实现瘦脸美颜 交互式的液化效果原理来自 Gustafsson A. Interactive image warping[D]. , 1993. 2、原理分析 上面描述很清晰了&#xff0c;鼠标初始在 C&#xff0c;也即…

大疆上云API基于源码部署

文章目录 大疆上云API基于源码部署注意事项1、学习官网2、环境准备注意事项3、注册成为DJI开发者4、下载前后端运行所需要的包/依赖前端依赖下载后端所需要的Maven依赖包 用到的软件可以在这里下载5、MySQL数据库安装安装MySQL启动MySQL服务在IDEA中配置MySQL的连接信息 6、Red…

AI学习路线图-邱锡鹏-神经网络与深度学习

1 需求 神经网络与深度学习 2 接口 3 示例 4 参考资料

行业案例:高德服务单元化方案和架构实践

目录 为什么要做单元化 高德单元化的特点 高德单元化实践 服务单元化架构 就近接入实现方案 路由表设计 路由计算 服务端数据驱动的单元化场景 总结 系列阅读 为什么要做单元化 单机房资源瓶颈 随着业务体量和服务用户群体的增长,单机房或同城双机房无法支持服…

【计算机网络】lab7 TCP协议

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;计算机网络_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 实验目的…

docker中jenkins流水线式部署GitLab中springboot项目

本质就是将java项目拉取下来&#xff0c;并自动打包成docker镜像&#xff0c;运行 首先启动一个docker的jenkins 如果没有镜像使用我的镜像 通过网盘分享的文件&#xff1a;jenkins.tar 链接: https://pan.baidu.com/s/1VJOMf6RSIQbvW_V1zFD7eQ?pwd6666 提取码: 6666 放入服…

【初识扫盲】厚尾分布

厚尾分布&#xff08;Fat-tailed distribution&#xff09;是一种概率分布&#xff0c;其尾部比正态分布更“厚”&#xff0c;即尾部的概率密度更大&#xff0c;极端值出现的概率更高。 一、厚尾分布的特征 尾部概率大 在正态分布中&#xff0c;极端值&#xff08;如距离均值很…

小程序租赁系统

内容概要 小程序租赁系统&#xff0c;听起来很复杂&#xff0c;但其实就是为那些想要快速搭建业务的人提供一个便捷的工具。随着移动互联网的迅猛发展&#xff0c;越来越多的企业和创业者开始寻找效率和灵活性&#xff0c;而小程序正好满足了这种需求。据统计&#xff0c;过去…

高可用虚拟IP-keepalived

个人觉得华为云这个文档十分详细&#xff1a;使用虚拟IP和Keepalived搭建高可用Web集群_弹性云服务器 ECS_华为云 应用场景&#xff1a;虚拟IP技术。虚拟IP&#xff0c;就是一个未分配给真实主机的IP&#xff0c;也就是说对外提供数据库服务器的主机除了有一个真实IP外还有一个…

工厂人员定位管理系统方案(二)人员精确定位系统架构设计,适用于工厂智能管理

哈喽~这里是维小帮&#xff0c;提供多个场所的定位管理方案&#xff0c;如需获取工厂人员定位管理系统解决方案可前往文章最下方获取&#xff0c;如有项目合作及技术交流欢迎私信我们哦~撒花 在上一篇文章中&#xff0c;我们初步探讨了工厂人员定位管理系统的需求背景以及定位方…

虚假星标:GitHub上的“刷星”乱象与应对之道

在开源软件的世界里&#xff0c;GitHub无疑是最重要的平台之一。它不仅是一个代码托管平台&#xff0c;也是一个社交网络&#xff0c;允许开发者通过“点赞”&#xff08;即加星&#xff09;来表达对某个项目的喜爱和支持&#xff0c;“星标”&#xff08;Star&#xff09;则成…

RK3568 Android 13 内置搜狗输入法小计

问&#xff1a;为什么写&#xff1f; 答&#xff1a;网上搜出来的都试过了&#xff0c;不行&#xff01;下面直接上代码和注意事项&#xff01; 首先到这个目录&#xff08;/RK3568/Rockchip_Android13_SDK_Release/device/rockchip/rk356x/tl3568_evm/preinstall&#xff09…

GO语言实现KMP算法

前言 本文结合朱战立教授编著的《数据结构—使用c语言&#xff08;第五版&#xff09;》&#xff08;以下简称为《数据结构&#xff08;第五版&#xff09;朱站立》&#xff09;中4.4.2章节内容编写&#xff0c;KMP的相关概念可参考此书4.4.2章节内容。原文中代码是C语言&…

基于springboot的疫情网课管理系统

作者&#xff1a;学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”&#xff0c;支持远程部署调试、运行安装。 项目包含&#xff1a; 完整源码数据库功能演示视频万字文档PPT 项目编码&#xff1…

FFmpeg硬件解码

使用FFmpeg进行硬件解码时&#xff0c;通常需要结合FFmpeg的API和硬件加速API&#xff08;如CUDA、VAAPI、DXVA2等&#xff09;。以下是一个简单的C代码示例&#xff0c;展示如何使用FFmpeg进行硬件解码。这个示例使用了CUDA作为硬件加速的后端。 1. 安装FFmpeg和CUDA 确保你…

unity如何在urp管线下合并spine的渲染批次

对于导入unity的spine来说,他会对每个spine生成独有的材质,虽然他们使用的是同一个shader,但由于附带独有的贴图,这样在项目使用中会由于材质贴图不同而导致无法合批. 而为什么选用urp,因为在built-in管线中,对于GPU-instancing,即使通过使用图集的方式统一了贴图,也会由于spi…

【Elasticsearch】批量操作:优化性能

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探…

深入 Flutter 和 Compose 在 UI 渲染刷新时 Diff 实现对比

众所周知&#xff0c;不管是什么框架&#xff0c;在前端 UI 渲染时&#xff0c;都会有构造出一套相关的渲染树&#xff0c;并且在 UI 更新时&#xff0c;为了尽可能提高性能&#xff0c;一般都只会进行「差异化」更新&#xff0c;而不是对整个 UI Tree 进行刷新&#xff0c;所以…

Docker 的安装和基本使用[SpringBoot之Docker实战系列] - 第535篇

历史文章&#xff08;文章累计530&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

介绍下不同语言的异常处理机制

Golang 在Go语言中&#xff0c;有两种用于处于异常的机制&#xff0c;分别是error和panic&#xff1b; panic panic 是 Go 中处理异常情况的机制&#xff0c;用于表示程序遇到了无法恢复的错误&#xff0c;需要终止执行。 使用场景 程序出现严重的不符合预期的问题&#x…