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

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. 使用智能指针可以避免手动管理内存,推荐使用

http://www.kler.cn/a/502334.html

相关文章:

  • 目标检测中的Bounding Box(边界框)介绍:定义以及不同表示方式
  • React中ElementFiber对象、WorkInProgress双缓存、ReconcileRenderCommit、第一次挂载过程详解
  • golang OpcUaClient
  • 用HTML + CSS实现太极图
  • ARP-Batch-Retargeting 部署实战
  • 【集成学习】Bagging、Boosting、Stacking算法详解
  • Golang——协程同步
  • flink kafka 版本对照表
  • 给DevOps加点料:融入安全性的DevSecOps
  • linux---Nginx详细教程(包含安装,网站部署)
  • 2008-2020年各省社会消费品零售总额数据
  • vim基本命令(vi、工作模式、普通模式、插入模式、可视模式、命令行模式、复制、粘贴、插入、删除、查找、替换)
  • PHP答题考试系统:智慧教育的璀璨明珠
  • pyqt鸟瞰
  • 【三维数域】三维数据调度-负载均衡和资源优化
  • 2023-2024 学年 广东省职业院校技能大赛(高职组)“信息安全管理与评估”赛题一
  • 面经学习-操作系统-上下文切换
  • 服务器出现蓝屏现象的原因有什么?
  • Java URLClassLoader类来动态加载数据库驱动jar
  • Linux的用户管理
  • 数据结构(Java版)第八期:LinkedList与链表(三)
  • OpenCV的图像分割
  • 利用开源AI智能名片2+1链动模式S2B2C商城小程序拓展社交电商的深度实践探索
  • uniapp 预加载分包,减少loading
  • 【高阶数据结构】位图
  • 【react进阶】create-react-app高阶配置