QT编程之HTTP服务端与客户端技术

一、HTTP 服务器实现方案

  1. QtWebApp 集成

    • QtWebApp源码httpserver 目录导入项目,并在 .pro 文件中添加 include ($$PWD/httpserver/httpserver.pri)‌。
    • 配置 WebApp.ini 文件定义服务参数(IP、端口、线程池等),通过 HttpListener 类启动监听‌。
    • 自定义 RequestMapper 类处理不同 URL 路径的请求,继承 HttpRequestHandler 实现业务逻辑‌。
    • 详细使用方法参考:QtWebApp - wuyuan2011woaini - 博客园
  2. 原生 Qt 网络模块

    • 使用 QTcpServer 监听端口,通过 incomingConnection() 接收客户端连接‌。
    • 解析 HTTP 请求头(如 QByteArray 处理报文),动态生成响应内容(如 HTML/JSON)‌。

二、HTTP 客户端实现方案

Qt中的QNetworkAccessManager是网络请求管理的核心类,用于异步处理HTTP/HTTPS等协议通信。以下是其关键特性及使用方式:

1. ‌核心功能
  • 单例管理‌:整个Qt应用只需一个实例即可管理所有网络请求,负责维护代理、缓存等全局配置‌。
  • 请求调度‌:支持GET、POST、PUT、DELETE等标准HTTP方法,并通过队列管理并发请求(如HTTP协议默认同一主机/端口允许6个并发请求)‌。
2. ‌基本使用步骤
复制代码
// 创建实例
QNetworkAccessManager *manager = new QNetworkAccessManager(this);

// 发送GET请求示例
connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {
    // 处理响应数据
    QByteArray data = reply->readAll();
    reply->deleteLater(); // 避免内存泄漏
});
manager->get(QNetworkRequest(QUrl("http://example.com")));

通过finished信号接收响应,使用QNetworkReply对象解析返回数据和元信息(如HTTP头)‌。

复制代码
QNetworkAccessManager manager;  
QUrl url("http://example.com/api/resource");  
QNetworkRequest request(url);  
  
// 添加鉴权信息(与 GET 请求相同)  
QByteArray authHeaderData = "Basic " + yourBase64EncodedAuthString;  
request.setRawHeader(QByteArray("Authorization"), authHeaderData);  
  
// 准备 POST 数据(这里只是一个简单的示例)  
QByteArray postData = "key1=value1&key2=value2";  
  
// 发送 POST 请求  
QNetworkReply *reply = manager.post(request, postData);
3. ‌异步处理与资源管理
  • 异步API‌:所有请求非阻塞主线程,通过信号槽机制通知完成状态‌。
  • 资源释放 ‌:需手动调用reply->deleteLater()释放QNetworkReply对象,不可在槽函数中直接delete‌。
4. ‌高级配置
  • 代理与缓存 ‌:可通过setProxy()setCache()方法设置全局代理及缓存策略‌。
  • SSL加密连接 ‌:使用connectToHostEncrypted()建立HTTPS连接,支持自定义SSL配置‌。
5. ‌错误处理

监听errorOccurred信号处理网络错误:

复制代码
connect(reply, &QNetworkReply::errorOccurred, [](QNetworkReply::NetworkError code) {
    qDebug() << "Error:" << code;
})‌;
6. ‌超时控制

通过QTimer实现异步请求超时机制:

复制代码
QTimer::singleShot(5000, ‌:ml-search[reply] {  // 5秒超时
    if (reply && reply->isRunning()) {
        reply->abort();
        qDebug() << "Request timeout";
    }
})‌;
7. ‌鉴权处理

在请求头中添加鉴权信息(如Authorization):

复制代码
QNetworkRequest request;
request.setRawHeader("Authorization", "Bearer token123");
manager->get(request)‌:ml-citation{ref="3" data="citationList"}。
8. ‌设置请求头

如果你需要设置请求头(例如,设置Content-Typeapplication/json):

复制代码
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

8. ‌同步阻塞网络请求

QEventLoop在接收网络返回内容结束之前,一直阻塞等待。

复制代码
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>

struct TestA {
    int data; // 示例数据
    // 其他字段
};
 
class NetworkManager : public QObject {
    Q_OBJECT
 
public:
    NetworkManager(QObject* parent = nullptr) : QObject(parent) {
        manager = new QNetworkAccessManager(this);
    }
 
    TestA getTestA() {
        QEventLoop loop;
        TestA result;
 
        // 发起网络请求
        QNetworkRequest request(QUrl("http://www.example.com"));
        QNetworkReply* reply = manager->get(request);
 
        // 连接槽函数解析数据
        connect(reply, &QNetworkReply::finished, [&]() {
            if (reply->error() == QNetworkReply::NoError) {
                QByteArray response = reply->readAll();
                result = parseResponse(response);
            } else {
                qWarning() << "Network error:" << reply->errorString();
            }
            reply->deleteLater();
            loop.quit();
        });
 
        // 阻塞等待网络请求完成
        loop.exec();
 
        return result;
    }
 
private:
    QNetworkAccessManager* manager;
 
    TestA parseResponse(const QByteArray& response) {
        TestA parsedData;
        // 假设解析为整数数据
        parsedData.data = QString(response).toInt();
        return parsedData;
    }
};

#include <QCoreApplication>
 
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
 
    NetworkManager networkManager;
    TestA data = networkManager.getTestA();
    qDebug() << "Received data:" << data.data;
 
    return a.exec();
}
9. ‌异步非阻塞网络请求

通过设置回调函数,将网络请求应答回调出去。

复制代码
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QDebug>
#include <functional>
 
struct TestA {
    int data; // 示例数据
    // 其他字段
};

class NetworkManager : public QObject {
    Q_OBJECT
 
public:
    using Callback = std::function<void(const TestA&)>;
 
    NetworkManager(QObject* parent = nullptr) : QObject(parent) {
        manager = new QNetworkAccessManager(this);
    }
 
    void getTestA(const Callback& callback) {
        // 发起网络请求
        QNetworkRequest request(QUrl("http://www.example.com"));
        QNetworkReply* reply = manager->get(request);
 
        // 连接槽函数解析数据
        connect(reply, &QNetworkReply::finished, this, [this, reply, callback]() {
            TestA result;
            if (reply->error() == QNetworkReply::NoError) {
                QByteArray response = reply->readAll();
                result = parseResponse(response);
            } else {
                qWarning() << "Network error:" << reply->errorString();
            }
            reply->deleteLater();
            callback(result);
        });
    }
 
private:
    QNetworkAccessManager* manager;
 
    TestA parseResponse(const QByteArray& response) {
        TestA parsedData;
        // 假设解析为整数数据
        parsedData.data = QString(response).toInt();
        return parsedData;
    }
};

#include <QCoreApplication>
 
void handleResult(const TestA& data) {
    qDebug() << "Received data:" << data.data;
    QCoreApplication::quit();
}
 
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
 
    NetworkManager networkManager;
    networkManager.getTestA(handleResult);
 
    return a.exec();
}
相关推荐
摸鱼仙人~2 分钟前
Redux Toolkit 快速入门指南:createSlice、configureStore、useSelector、useDispatch 全面解析
开发语言·javascript·ecmascript
小灰灰搞电子7 分钟前
Qt多线程访问同一个数据库源码分享(基于Sqlite实现)
数据库·qt·sqlite
onlooker666618 分钟前
Go 语言底层(四) : 深入 Context 上下文
开发语言·数据库·golang
Bardb27 分钟前
01__C++入门
c++·qt
若水晴空初如梦1 小时前
QT聊天项目DAY14
开发语言·qt
幼稚园的山代王1 小时前
python3基础语法梳理(一)
开发语言·python
幼稚诠释青春1 小时前
面试实例题
java·开发语言
weixin_457665392 小时前
C++11新标准
开发语言·c++
阿蒙Amon2 小时前
C#封装HttpClient:HTTP请求处理最佳实践
开发语言·http·c#
大白爱琴2 小时前
使用python进行图像处理—像素级操作与图像算术(4)
开发语言·图像处理·python