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();
}
相关推荐
喵个咪3 天前
Go-Wind HTTP 服务器从入门到精通
后端·http·go
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Goodbye9 天前
大模型无状态架构:从 HTTP 协议到 Harness AI 工程的深度解析
http
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt