Skip to content

SunRain/QCurl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

188 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

QCurl

基于 Qt6 和 libcurl 的现代 C++ 网络库,提供高性能、类型安全的 HTTP Core API 与可选 Extras / 显式 Extras / Preview。

Qt6 C++17 libcurl CMake License


发布状态与 1.0.0 first stable 边界

QCurl 1.0.0 first stable 的稳定承诺范围以默认安装面为准:QCURL_INSTALL_HEADERS + QCurlConfig.h。这些头文件构成 Core API,进入默认 find_package(QCurl) / QCurl::QCurl consumer contract。shared library 与 static library 都属于本次 1.0.0 first stable 发布形态;whole project、WebSocket 和 Diagnostics 不随 Core 一起宣布 Stable。

层级 发布含义 当前范围
Core 默认安装,作为 1.0.0 first stable 维护 API / ABI QCNetworkAccessManagerQCCookieQCCookieAsyncResultQCNetworkRequestQCNetworkRequestConfigQCNetworkReply、TLS / proxy / timeout / retry / redirect / transfer 配置、HTTP method / version / error / priority、lane-aware scheduler、cache policy type header、Cache lookup concrete API、Multipart builder、QCNetworkLoggerQCNetworkDefaultLoggerQCNetworkCancelToken、Middleware base、ConnectionPool 管理面
Blocking Extras 显式安装,提供同步 value-result 工具;不混入默认 Core QCBlockingNetworkClientQCBlockingNetworkResultQCBlockingCookieStore
Test Support 显式安装,用于测试支持,不作为生产运行时网络栈能力表述 QCNetworkMockHandlerQCNetworkCapturedRequestQCNetworkTestSupport
Other Extras / Preview 显式安装或条件安装;不属于默认 Core 稳定承诺 Diagnostics、Middleware Extras、WebSocket

除非文档明确标注为 Core,示例中引用 QCURL_INSTALL_HEADERS_EXTRAS 的头文件时,都应视为显式 opt-in 的非默认发行面。完整边界见 docs/arch/public-header-boundary.mddocs/arch/1.0-first-stable-release-contract.mddocs/arch/1.0-first-stable-readiness-report.md

为什么选择 QCurl?

现代化架构 Core HTTP 可选扩展 Qt 友好
CMake + RAII + C++17 HTTP/1.1、HTTP/2、HTTP/3 capability 显式 Extras / Preview QObject 线程归属与事件循环合同

功能分层

Core

  • CMake 构建系统 - 跨平台支持,自动依赖检测
  • 统一 Reply 架构 - QCNetworkReply 作为 Core 异步响应入口,统一承载状态、信号、读取和错误信息
  • RAII 资源管理 - Core 资源生命周期由 public API 合同和测试门禁约束,调用方无需直接管理 libcurl handle
  • C++17 特性 - std::optionalstd::chrono[[nodiscard]]enum class
  • HTTP/1.1、HTTP/2、HTTP/3 capability - HTTP/3 取决于运行时 libcurl / QUIC backend
  • SSL/TLS - 可配置证书验证、客户端证书、CA 路径
  • 代理支持 - HTTP、HTTPS、SOCKS4/4A、SOCKS5
  • Canonical Request API - QCNetworkRequest + QCNetworkAccessManager::head()/get()/post()/put()/patch() 一套入口覆盖配置与发送
  • 请求对象配置 - QCNetworkRequest::setRawHeader()/setTimeout()/setPriority()/setLane() 支持链式配置;QCNetworkRedirectConfigQCNetworkTransferConfig 聚合重定向和传输配置
  • 请求重试 - 指数退避算法,自动处理临时性错误
  • lane-aware 调度 - lane reservation + DRR 公平调度 + 按 lane 精准取消
  • 缓存策略类型 - QCNetworkCachePolicyQCNetworkRequest 的 Core 配置类型
  • Cache lookup API - QCNetworkCacheQCNetworkMemoryCacheQCNetworkDiskCache 提供 lookup(url, ReadMode),返回 Miss / FreshHit / StaleHit
  • Multipart/form-data builder - QCMultipartFormData / QCNetworkMultipartBody 生成 body,再通过 post() 发送
  • 日志接口 - QCNetworkLogger 提供 Core 级日志抽象与 debug trace 脱敏入口
  • 默认日志实现 - QCNetworkDefaultLogger 提供 Core 级默认 logger helper
  • 取消令牌 - QCNetworkCancelToken 提供 reply-level 批量取消和自动超时取消
  • Middleware base - QCNetworkMiddleware 作为 Core 拦截与观测基类进入默认安装面;通用具体 middleware 通过 Other Extras opt-in 使用
  • ConnectionPool 管理面 - 连接池配置、统计和资源控制接口使用 accessor / shared-data API
  • 流式下载/上传 - QCNetworkDownloadToDeviceJob 与 manager-level post()/put() raw-body device overload 支持大文件
  • 断点续传 - QCNetworkResumableDownloadJob 基于 HTTP Range 请求恢复下载
  • Core cookie model - QCCookie 是 Core public cookie 值类型;默认 consumer 不需要 QtNetwork cookie 类型
  • Cookie async result - QCCookieOperationResult / QCCookieExportResult 是 manager cookie async signal 与 QFuture 的 Core 值结果

Blocking Extras

  • 同步 value-result client - QCBlockingNetworkClient / QCBlockingNetworkResult 通过显式 BlockingExtrasDevelopment 安装,不随默认 Core 安装。
  • 受限内存响应体 - QCBlockingRequestOptions::maxInMemoryBodyBytes() 默认限制内存响应体;超过上限返回 NetworkError::BodyTooLarge
  • 大响应下载 - 大响应使用 QCBlockingNetworkClient::downloadToDevice() 写入调用方提供的 QIODevicebody() 保持为空,bytesReceived() 记录实际接收字节数。
  • 诊断错误边界 - Blocking Extras 使用 BodyTooLargeOutputDeviceErrorInputDeviceErrorReplayNotSupported 等明确错误;curl code 只通过 diagnosticCurlCode() 作为辅助诊断,不作为主判断 API。
  • Cookie snapshot / delta - QCBlockingCookieStore 提供 Blocking Extras cookie 边界,不访问 live manager cookie store。

Test Support

  • MockHandler Test Support - QCNetworkMockHandlerQCNetworkCapturedRequestQCNetworkTestSupport 通过显式 TestSupportDevelopment 安装,供测试程序 opt-in 使用。

Other Extras / Preview

  • Diagnostics 扩展诊断 - QCNetworkDiagnostics 通过显式 OtherExtrasDevelopment 安装;QtNetwork 依赖只由 QCurl::OtherExtras 承担,ping/traceroutedetails schema 仍不作为默认 Core 稳定合同。
  • Middleware Extras - QCNetworkMiddlewareExtras 通过显式 OtherExtrasDevelopment 安装;默认 Core 只承诺 QCNetworkMiddleware base。
  • WebSocket - 客户端实现包含压缩、自动重连和连接池能力,条件进入 Other Extras;当前仍不属于默认 Core install surface。

性能基准说明

性能数字需要绑定具体 benchmark 版本、依赖版本、网络环境和日期。未绑定证据的数字不应作为 1.0.0 first stable 稳定发布承诺。


📦 系统要求

依赖 版本要求 说明
CMake 3.16+ 构建系统
Qt6 6.2+ Core consumer 需要 QtCore;Other Extras diagnostics 需要 QtNetwork
libcurl 7.85.0+ WebSocket 需 7.86.0+;HTTP/3 推荐 8.16.0+ 且带 QUIC backend
编译器 C++17 GCC 11+、Clang 14+、MSVC 2019+

🚀 快速开始

构建安装

git clone https://github.com/SunRain/QCurl.git
cd QCurl
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
cmake --install build --prefix "$PWD/stage"

发布合同提示:

  • 1.0.0 first stable 只承诺 Core install surface。
  • Blocking Extras / Test Support / Other Extras 需要发行包显式安装对应 component,不随默认 Core 隐式安装。
  • 当前 lane-aware scheduler 已纳入 QCurl 1.0.0 / SOVERSION 1 first stable Core 合同;本发布线不提供旧 2.x/3.x 兼容层。

代码示例

1. 简单 GET 请求

#include <QCNetworkAccessManager.h>
#include <QCNetworkRequest.h>

QCurl::QCNetworkAccessManager manager;
QCurl::QCNetworkRequest request(QUrl("https://api.example.com/data"));
request.setRawHeader("Authorization", "Bearer token")
    .setTimeout(std::chrono::seconds(30));

auto *reply = manager.get(request);

connect(reply, &QCurl::QCNetworkReply::finished, [reply]() {
    if (reply->error() == QCurl::NetworkError::NoError) {
        if (const auto data = reply->readAll(); data.has_value()) {
            qDebug() << "Response:" << *data;
        }
    }
    reply->deleteLater();
});

2. WebSocket 连接(Preview)

说明:WebSocket 使用 QCURL_INSTALL_HEADERS_EXTRAS 中的扩展头。 它可以作为 Preview 功能使用,但不属于 1.0.0 first stable 承诺。

#include <QCWebSocket.h>
#include <QCWebSocketCompressionConfig.h>
#include <QCWebSocketReconnectPolicy.h>

QCurl::QCWebSocketOptions options;
options.setCompressionConfig(QCurl::QCWebSocketCompressionConfig::defaultConfig());
options.setReconnectPolicy(QCurl::QCWebSocketReconnectPolicy::standardReconnect());

auto *socket = new QCurl::QCWebSocket(QUrl("wss://echo.websocket.org"), options);

connect(socket, &QCurl::QCWebSocket::connected, [socket]() {
    socket->sendTextMessage("Hello WebSocket!");
});

connect(socket, &QCurl::QCWebSocket::textMessageReceived, [](const QString &msg) {
    qDebug() << "Received:" << msg;
});

socket->open();

3. 文件上传(Core Multipart)

QCMultipartFormData.h 属于 Core install surface,默认 installed consumer 可以直接使用该 builder。

#include <QCMultipartFormData.h>
#include <QCNetworkMultipartBody.h>

QCurl::QCMultipartFormData formData;
formData.addTextField("userId", "12345");
formData.addFileField("avatar", "/path/to/photo.jpg");

QCurl::QCNetworkRequest uploadRequest(QUrl("https://api.example.com/upload"));
auto body = QCurl::QCNetworkMultipartBody::fromFormData(formData);
uploadRequest.setRawHeader("Content-Type", body.contentType());
auto *reply = manager.post(uploadRequest, body.data());

4. 内存请求体(JSON / form-urlencoded)

QCNetworkBody 会随请求体保存匹配的 Content-Typepost() / put() / patch() 接收 QCNetworkBody 时,若请求尚未显式设置 Content-Type,会自动补齐;若已设置, 则尊重请求里的显式值。

#include <QCNetworkBody.h>

QCurl::QCNetworkRequest formRequest(QUrl("https://api.example.com/form"));
auto formBody = QCurl::QCNetworkBody::fromFormUrlEncoded(
    QList<QPair<QString, QString>>{
        {QStringLiteral("tag"), QStringLiteral("one")},
        {QStringLiteral("tag"), QStringLiteral("two")},
    });
auto *formReply = manager.post(formRequest, formBody);

5. Lane-aware Scheduler

调度配置入口在 QCNetworkAccessManager 上;请求 lane 使用 typed key,未注册 lane 会 fail-closed。

#include <QCNetworkLaneKey.h>
#include <QCNetworkSchedulerPolicy.h>

QCurl::QCNetworkSchedulerPolicy policy = QCurl::QCNetworkSchedulerPolicy::defaultPolicy();
policy.setMaxConcurrentRequests(6);
policy.setMaxRequestsPerHost(2);

QString schedulerError;
QCurl::QCNetworkSchedulerPolicy::LaneConfig controlLane;
controlLane.setWeight(3);
controlLane.setQuantum(1);
controlLane.setReservedGlobal(1);
controlLane.setReservedPerHost(1);
if (!policy.setLaneConfig(QCurl::QCNetworkLaneKey::control(), controlLane, &schedulerError)) {
    qWarning() << schedulerError;
}

QCurl::QCNetworkSchedulerPolicy::LaneConfig transferLane;
transferLane.setWeight(1);
transferLane.setQuantum(1);
if (!policy.setLaneConfig(QCurl::QCNetworkLaneKey::transfer(), transferLane, &schedulerError)) {
    qWarning() << schedulerError;
}

if (!manager.setSchedulerPolicy(policy, &schedulerError)) {
    qWarning() << schedulerError;
}

QCurl::QCNetworkRequest controlRequest(QUrl("https://api.example.com/manifest"));
controlRequest.setLane(QCurl::QCNetworkLaneKey::control())
    .setPriority(QCurl::QCNetworkRequestPriority::High);

QCurl::QCNetworkRequest transferRequest(QUrl("https://cdn.example.com/chunk.bin"));
transferRequest.setLane(QCurl::QCNetworkLaneKey::transfer())
    .setPriority(QCurl::QCNetworkRequestPriority::Low);

const auto stats = manager.schedulerStatistics();
qDebug() << "pending=" << stats.pendingRequests()
         << "running=" << stats.runningRequests();

const auto cancelResult = manager.cancelLaneRequests(
    QCurl::QCNetworkLaneKey::transfer(),
    QCurl::QCNetworkAccessManager::SchedulerCancelScope::PendingAndRunning);
if (!cancelResult.isSuccess()) {
    qWarning() << cancelResult.error();
}

简要提示:

  • lane 可以理解成“请求车道”:先按车道分组,再在车道内按优先级排序。
  • Critical 现在只影响同一条 lane 内的启动顺序;若需要给控制类请求留保底名额,请使用 lane reservation。
  • QCNetworkLaneKey::fromName(name, &lane, &error) 可创建自定义 lane;解析失败不会返回 invalid sentinel,成功后必须先写入 QCNetworkSchedulerPolicy
  • cancelLaneRequests() 返回 QCNetworkLaneCancelResultPendingOnly 只清 pending/deferred,PendingAndRunning 会连 running 一并取消。
  • scheduler policy 和统计接口必须在 manager owner thread 调用;跨线程配置请显式投递到 owner thread。

完整说明、请求时序图和 Control / Transfer / Background 配置建议统一参考:

  • docs/user/lane-scheduler.md

⚡ 性能回归入口

性能数字只在绑定具体 benchmark 版本、依赖版本、网络环境和日期时才作为发布证据。 当前 README 不把固定延迟或吞吐数字写成 1.0.0 first stable 稳定承诺。

性能回归与能力证据以以下入口为准:

  • docs/reference/performance.md
  • docs/reference/benchmarks.md
  • tests/libcurl_consistency/run_gate.py --suite all --with-ext --build

🧪 测试与验证

测试运行与门禁以 docs/dev/build-and-test.md 为准。发布前使用 full release gate、shared/static public-api gate、ABI gate、metadata scan 和 git diff --check 形成可复验结果。

本 README 不维护固定测试数量、通过率或一次性 gate 输出;这些数字必须绑定具体 build、依赖版本、环境和日期后,放入维护者证据文档或 CI artifacts。


📚 文档

文档 说明
docs/README.md 文档入口(按读者角色分层)
SYSTEM_DOCUMENTATION.md 维护者 Architecture overview
examples/README.md 示例集合与运行方式

🔧 项目集成

CMake

find_package(QCurl CONFIG REQUIRED)
target_link_libraries(your_app PRIVATE QCurl::QCurl)

使用 staging prefix 验证独立 consumer 时:

cmake -S your-app -B build-your-app -DCMAKE_PREFIX_PATH=/path/to/QCurl/stage
cmake --build build-your-app

默认构建发布 shared library。Static library 需要显式 opt-in:

cmake -S . -B build-static -DCMAKE_BUILD_TYPE=Release -DQCURL_BUILD_SHARED_LIBS=OFF
cmake --build build-static --target QCurl qcurl_public_api_self_compile
ctest --test-dir build-static -L '^public-api$' --output-on-failure
ctest --test-dir build-static -L '^public-api-slow$' --output-on-failure

Static 路径已纳入 full release gate。正式打包前仍以 scripts/run_release_gate.py --tier full --build-dir build --static-build-dir build-static 的最新输出为准;即使 static gate 通过,也只声明 Core static library ready,不声明 whole project static library ready。

Static consumer 若只使用 QCNetworkRequestPriority 等头文件类型,并需要 Qt 元类型按名称可见,应在 main() 早期调用一次 QCurl::initialize()。shared consumer 通常不需要手动调用;该函数幂等,调用后不会创建网络对象或启动 scheduler。

pkg-config

g++ your_app.cpp $(pkg-config --cflags --libs qcurl) -o your_app

🤝 贡献

欢迎 Pull Request!

  • 贡献指南:CONTRIBUTING.md
  • 行为准则:CODE_OF_CONDUCT.md
  • 安全策略:SECURITY.md
  • 支持与反馈:SUPPORT.md

📜 许可证

MIT License - 自由使用、修改、分发


🙏 致谢

  • libcurl - 强大的网络传输库
  • Qt - 优雅的跨平台 C++ 框架

QCurl - Qt6 + libcurl Core HTTP library

About

Qt binding for libcurl

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors