Skip to content

Releases: Hical61/Hical

v2.6.5

12 Jun 10:21

Choose a tag to compare

Added

  • Expect: 100-continue 支持#8):Router 新增 exists() 路由预检方法,HttpSessionImpl 解析 Expect 头;路由不存在返回 404,body 大小超限返回 413,均通过时发送 100 Continue 让客户端传输 body。配套集成测试

Changed

  • setBody API 变更#9):setBody(body) 单参版本不再自动覆写 Content-Type,得用双参 setBody(body, contentType) 手动传。框架内部所有内置错误响应(notFound/badRequest/serverError/rangeNotSatisfiable)和调用点都改成显式传参了
  • OpenApiDocument::generateString() 线程安全:改成按值返回,之前 invalidate() 跨线程调的时候跟 generateString() 并发读会有 data race
  • /docs 页面缓存:加了 Cache-Control: public, max-age=3600
  • recommendedMaxConnections 上限放开:从 65535 提到 100 万

Performance

  • 空闲长连接内存砍半:搞了个 ReadBufferPool(thread_local 无锁池,BufferHandle RAII 接管借还),空闲时不占 readBuf,来了请求借一块、写完了还回去。空闲连接从 17.44 KB 降到 ~8 KB。顺带把 GenericConnection::inputBuffer_ 改成 optional<PmrBuffer> 懒分配,readLoop 第一次进来才创建,每个空闲连接再省 ~2 KB。按百万长连接算总共省了大概 9.5 GB
  • HeaderMap::toLower() 编译期 256 查表constexpr array 替代挨个 tolower(),头部大小写归一化热路径加速
  • Router::urlDecode() 编译期 hex 查表:256 条 constexpr 查表替代运行时分支判断,URL 解码加速
  • HttpSessionImpl Connection 头预扫描:解析 header 时顺手把 Connection 值抓出来,省了后面单独 O(n) 扫一遍

Fixed

  • burst 建连时连接数限制失效:原来逻辑是先 load 判断再 fetch_add,但 handleSessioncoSpawn 异步投递,高速建连时计数跟不上,限流失效。改成 accept 处先 fetch_add 占位,超限就 fetch_sub 退回来 close socket,AcceptGuard RAII 保底不回漏;maxConnections_ 改成 atomic 让多 acceptor 并发没问题
  • WS 升级路径堆损坏:一串三个生命周期 bug——PoolSlots 线程退出时裸指针没释放(LeakSanitizer 能抓到)、IOCP 两阶段析构后 readBuf 还到已销毁的 tlsPool、socket move 后 idleEntry 还挂在 IdleScanner 链表上。修法:move socket 前把 readBuf 和 Guard 都先 release 掉,handleWebSocket 签名改成接 string 参数,从根上断了对 readBuf 的引用
  • MinGW thread_local 析构时序炸堆:CI 上 msys2-gcc 测试跑完了退进程时爆 0xC0000374 或 SEGFAULT。原因是 PoolSlots 的析构在 DLL TLS 回调里跑,那时候 CRT 堆已经没了。修法:#ifndef __MINGW32__ 跳过 MinGW 下的 TLS 清理,进程退出 OS 自己收
  • AsyncFileSink 析构 data race:bgThread_ 成员声明在 flushRequests_ 前面,C++ 反向析构时 flushRequests_ 先被销毁,后台线程还在写它,TSan(Clang-20)抓到。把 bgThread_ 移到 flushRequests_ 后面,保证先 join 线程再销毁队列

Full Changelog: v2.6.4...v2.6.5

v2.6.4

30 May 13:32

Choose a tag to compare

Added

  • IdleScanner 集中式空闲连接扫描IdleScanner.h/cpp):per-io_context 单定时器 + 侵入式双链表替代 per-connection steady_timer 协程。Entry 嵌入协程栈(零堆分配),atomic<int64_t> lastActiveMs 无锁时间戳,Guard RAII 管理注册/注销生命周期。扫描间隔 max(1s, timeout/4)shutdown() 幂等取消 timer 切断与 timer_service 的依赖
  • StringPool 线程本地字符串对象池StringPool.h):5 级大小类(256/512/1K/2K/4K,各 32 槽),acquire(size) 返回池化 shared_ptr<string>,自定义 deleter 归还池中。send() 热路径池化避免 per-send malloc/free

Performance

  • IdleScanner 替代 per-connection timer:每连接独立 steady_timer 协程改为每 io_context 一个 IdleScanner 集中扫描,消除每连接的 timer 协程帧分配和 epoll_ctl 调用
  • EventLoopPool 最少连接分发nextLoop() 从 round-robin 改为挑选 connectionCount_ 最小的 loop,负载均衡更优
  • GenericConnection writeLoop drain 上限kMaxDrainBatch = 256 限制单轮 drain 节点数,防止突发队列饥饿 io_context 其他任务
  • DbConnectionPool acquire 快速淘汰acquire() 在持锁期间 isAlive() 预检,死连接收集后在锁外析构,避免无效 ping
  • idleCheckLoop 精确唤醒min_element 找到最早过期的空闲连接,timer 精确到期唤醒,idleCheckInterval 作为最大等待兜底,减少无效扫描
  • 响应前缀模板化:连接级 responsePrefix[128] 预构建 Server/Connection/Date 通用头部 wire bytes(~90B),keep-alive 请求 memcpy 替代 3 次 HeaderMap::insert + 序列化循环

Fixed

  • IdleScanner UAFidleScanners_ 声明顺序调整到 baseLoop_/ioPool_ 之前(scanner 比 io_context 后析构),timer_optional<steady_timer> + shutdown()~HttpServer() 中提前 cancel+reset timer,双向切断 scanner ↔ io_context 环形依赖
  • Windows IOCP 关服 SegFault:根因为 io_context::stop() 后 IOCP queue 中 abort completions 未 dispatch,~io_context() 强杀协程帧导致崩溃。最终方案:移除 io_context::stop() 调用,改为 cancel 所有 pending op + releaseWork() 释放 work_guard,协程自然退出后 run() 返回,queue 为空无两阶段销毁问题。同时修复 stop() 跨线程直接操作 timer/socket 的 UB(改为 post 到对应线程)、WS 升级后连接未注册到 scanner、gcLoop timer 提升为成员变量 gcTimer_ 确保可 cancel、IdleScanner 新增 closeAll() 关闭残留 socket

Full Changelog: v2.6.3...v2.6.4

v2.6.3

25 May 08:40

Choose a tag to compare

Added

  • HTTP 206 Range 请求StaticFiles 支持单范围 Range / If-Range ETag 条件请求,parseByteRange() 解析器,HttpResponse 新增 FileBody(path/offset/length)延迟异步分块发送,200 响应自动添加 Accept-Ranges: bytes
  • MimallocResource:可选 mimalloc 作为 PMR 最底层 upstream 分配器(HICAL_WITH_MIMALLOC CMake 选项,Conan/vcpkg 同步)

Changed

  • 统一命名风格m_ 前缀全部迁移为尾下划线,static constexpr 常量改用 k 前缀,枚举值补 h 前缀

Performance

  • GenericConnection MPSC 无锁写队列:写队列从 mutex + deque 升级为 Vyukov Intrusive MPSC Queue(wait-free O(1) push,摊销 O(1) pop),移除 isInLoopThread 分支和 lock_guardwriteLoop 批量 drain + seq_cst 反饥饿 re-check
  • TcpServer 连接表 per-loop 分片:全局 mutex + unordered_set 改为 per-loop LoopShard,idle 扫描/增删全程无锁
  • requestPool 无锁扩容createRequestPool() upstream 从 globalPool 改为 threadLocalPool,扩容零锁竞争
  • Worker 线程 CPU 亲和性绑核(Linux):EventLoopPool::start() 使用 pthread_setaffinity_np 将 worker 线程绑定到对应 CPU 核心,减少线程迁移导致的 TLB flush 和跨核 IPI
  • coSpawn recycling_allocator:所有 coSpawn() 重载改用 boost::asio::bind_allocator(recycling_allocator<void>(), ...) 包装 completion handler,thread_local 缓存避免高并发下重复 malloc/free
  • Idle timeout 条件初始化HttpSessionImpl 会话协程中 socketAlive / lastActiveMs 仅在 idleTimeout_ > 0 时分配,benchmark 场景设 setIdleTimeout(0) 后每连接省 3 次 make_shared + 1 个 timer 协程
  • SocketGuard 条件 shutdown:析构时仅在 cleanExit(正常 keep-alive 结束)才执行 shutdown(),避免对已断开连接的无效系统调用
  • HTTP 响应前缀模板化:连接级预构建 Server / Connection / Date 三个通用头部的 wire bytes(~90B),keep-alive 请求直接 memcpy 替代 3 次 HeaderMap::insert + 逐字段序列化循环;Date 值每秒最多一次 29B 覆写。新增 NativeResponse::serializeHeadTo(buf, prefix, prefixLen) 带前缀重载
  • TcpCorkGuard 文件响应合并小包writeFileResponse 路径新增 RAII TcpCorkGuard(Linux TCP_CORK / macOS TCP_NOPUSH / Windows no-op),将头部(~200B)与首个 64KB 文件 chunk 合并为一个 TCP 段发送,消除 TCP_NODELAY 下的小包问题
  • Docker 压测环境升级:启用 mimalloc 分配器(HICAL_WITH_MIMALLOC=ON)、RPS/RFS 网络亲和配置(bench-entrypoint.sh)、容器内存提升至 1GB + fd 上限 65536

Full Changelog: v2.6.2...v2.6.3

v2.6.2

18 May 01:05

Choose a tag to compare

Added

  • WsHub 广播管理器WsHub.h/cpp):连接注册/移除、房间分组、广播(shared_mutex + weak_ptr,跨线程 coSpawn 安全写入)
  • WebSocket Binary 消息sendBinary() / receiveMessage() 支持 Text/Binary 类型区分
  • WebSocket 写串行化acquireWrite() / releaseWrite() 防止 Ping 与消息并发 async_write
  • WebSocket 自定义关闭码closeAsync(code, reason) + 连接上下文 setContext() / getContext<T>()
  • WebSocket 心跳WsOptions 增加心跳间隔配置,集成 Ping 协程
  • WebSocket 子协议协商negotiateSubprotocol() 服务端优先匹配 + Sec-WebSocket-Protocol 响应头
  • WebSocket 参数路由findWsRoute() 返回 WsRouteMatch 支持 {param} 路径参数

Changed

  • WebSocket 代码消重 + 零分配优化receive() / receiveMessage() 合并为 receiveInternal(),消除 ~150 行重复;WsHub broadcast 合并为 broadcastImpl,接口统一改 string_view;透明哈希应用于 allowedOrigins / rooms;握手 key 拼接改栈上 char[64]sendTo() 单目标用 string move 替代 shared_ptr 控制块分配
  • vcpkg ports 完善:picohttpparser 声明为正式依赖(对应 vcpkg#51743),新增 ports/picohttpparser/ overlay port,移除 bundled 构建

Performance

  • GenericConnection WriteEntry 去虚函数化:内联 shared_ptr<string> 消除三层间接(shared_ptr→control block→WriteNode→虚函数),字段按访问频率重排 + alignas(64) 隔离 lastActiveTimeMs_
  • MemoryPool TrackedResource:四个 atomic 计数器各自 alignas(64) 消除 false sharing,新增 HICAL_ENABLE_MEMORY_TRACKING 条件编译(关闭时零开销)
  • Middleware MiddlewareTimingStats:热计数器 alignas(64) + 冷数据移至末尾

Fixed

  • AsioEventLoop::stop() 数据竞争quit_.exchange(true) 一次性门卫,确保 workGuard_.reset() / stop() 只执行一次
  • TSan 检出的 3 处数据竞争threadId_std::atomicAsioTimer::cancel() post 到 executor 线程执行;TcpServer::stop() acceptor 关闭 post 到 baseLoop_ 线程
  • HICAL_ENABLE_MEMORY_TRACKING CMake 选项缺失:补充 option(默认 ON) + PUBLIC compile definition,修复 4 个依赖 stats 的测试断言失败
  • WsDeflate.cpp 缺少 #include <cstdint>(PR #7

New Contributors

  • @toge made their first contribution in #7

Full Changelog: v2.6.0...v2.6.2

v2.6.1

14 May 02:48

Choose a tag to compare

Added

  • HTTP Date 头缓存thread_local 每秒更新一次,响应自动插入 RFC 7231 Date

Changed

  • hical_core 强制静态库:移除 WINDOWS_EXPORT_ALL_SYMBOLSadd_library 显式 STATIC
  • picohttpparser 条件集成:新增 HICAL_USE_SYSTEM_PICOHTTPPARSER 开关,include 从 PUBLIC 改为 PRIVATE
  • tests/CMakeLists.txt 重构:提取 hical_add_test() 函数消除重复样板
  • bench_main.cpp 精简为 TFB 专用:仅 /json + /plaintext
  • Conan/vcpkg 构建完善:Conan 新增 with_openapi 选项和宏透传,vcpkg port 新增 picohttpparser 系统依赖

Bug Fixes

  • fix: idleTimerLoop 悬空引用 (steady_timer& → shared_ptr<steady_timer>)
  • fix: idleTimerLoop cancel 后 yield 确保协程帧退出
  • fix: 回退 co_await post() yield,与 stopAllLoops 竞态导致 double-free
  • fix: HttpServer 成员析构顺序 (activeConnections_/draining_ 移到 baseLoop_ 之前)

Performance

  • perf: HTTP pipelining 优化:parse-before-read 快速路径 + 延迟 memmove

Build & Ports

  • chore: 添加 HICAL_USE_SYSTEM_PICOHTTPPARSER CMake 选项
  • chore: 新增 picohttpparser vcpkg port (对应 microsoft/vcpkg#51743)
  • chore: v2.6.1 构建系统整理与 Date 头缓存
  • chore: 分离 TFB 与框架对比 benchmark 入口

Full Changelog: v2.6.0...v2.6.1

v2.6.0

12 May 01:15

Choose a tag to compare

Breaking Changes

  • 移除 Boost.Beast 依赖:HTTP 解析/序列化和 WebSocket 全部替换为自研实现,native() 返回自研 NativeRequest / NativeResponse(原 Beast 类型)
  • 新增 zlib 依赖:WebSocket permessage-deflate 压缩需要 zlib

Added

  • 原生 HTTP 栈:集成 picohttpparser 替代 Beast HTTP parser(CPU 占比 10% → 0.08%),零拷贝 NativeRequeststring_view 引用连接级 readBuf,栈上 RequestHeaders 零堆分配),自研 NativeResponse 序列化(FixedBuffer<512> 栈缓冲 + scatter-gather I/O)
  • 自研 WebSocket 栈(RFC 6455 完整实现):手写帧解析/构造(WsFrame.h)、握手协议(WsHandshake.h)、permessage-deflate 压缩(WsDeflate.h/cpp,pimpl 封装 zlib),WebSocketSession 完全重写为 raw socket 实现,支持消息分片重组 + 控制帧穿插
  • HeaderMap 头部容器vector<pair> 实现,大小写不敏感查找,延迟 reserve(默认构造零堆分配)
  • SO_REUSEPORT 多 acceptor:每个 worker loop 独立 acceptor,accept 与 I/O 同线程零跨线程调度(Windows 自动回退单 acceptor)
  • 连接级 atomic 时间戳超时:替代 per-request timer,keep-alive 连接 epoll_ctl 调用降至 0
  • Chunked Transfer-Encoding 支持(RFC 7230)
  • 错误码统一映射Error.h/cpp):36 个 ErrorCode + NetworkError 结构,隔离上层对 Asio 错误码的直接依赖
  • coSpawn() 扩展:任意 executor 重载 + logOnException 替代 detached(未捕获异常输出到 stderr)
  • Docker 压测基础设施:bench-server / bench-wrk Dockerfile + docker-compose 编排

Changed

  • QPS 从 27K 提升至 159K(+489%),与 Cinatra/Drogon 持平
  • HttpServer 多 acceptor 架构acceptLoop 参数化支持并发运行,gracefulStop() 改为串行化关闭所有 acceptor
  • 热路径微优化:header 按长度+首字符快速过滤、响应头 insert() O(1) 替代 set() O(N)、attributes_ 延迟构造、FixedBuffer 从 4096 降至 512、200 OK 状态行预计算
  • RouteGroup 同步中间件链优化:纯同步场景零协程帧开销(10 层同步中间件仅比无中间件低 2.1%)

Fixed

  • readBuf 残留数据丢弃:TCP 粘包场景下 keep-alive 请求解析错误,bufUsed 移到循环外修复

Security

  • WebSocket 协议校验强化:客户端掩码强制检查、RSV 位限制、控制帧大小限制(≤125B)、zip bomb 防护
  • HTTP 头部/Body 大小限制:头部超限返回 431,Body 超限返回 413

Full Changelog: v2.5.2...v2.6.0

v2.5.2

10 May 02:04

Choose a tag to compare

Changed

  • Router 同步快速路径
    • 新增 Router::dispatchSync() 方法,同步注册的 handler 直接调用返回结果,跳过协程帧分配(~40-130ns/req)
    • 新增 RouteEntry 结构体(asyncHandler + 可选 syncHandler)替代裸 RouteHandler 存储
    • 新增 Router::resolveRoute() 内部方法,统一 URL 解码、路径深度校验、静态/参数路由查找、405 检测,dispatch()dispatchSync() 共用,消除 ~40 行重复代码和 404/405 场景的 double-lookup
    • dispatch() 也优先检查 syncHandler,有值时 co_return syncHandler(req) 跳过 co_await asyncHandler(req)
    • 同步 handler 注册只存 syncHandler,不再创建 asyncHandler wrapper,消除 std::function 拷贝
    • HttpSessionImpl.cpp 无中间件路径先尝试 dispatchSync(),有值直接返回(零协程帧),nullopt 时 fallback 到 co_await dispatch()
  • GenericConnection 编译防火墙
    • 模板方法实现从 GenericConnection.h(~780 行)提取到 GenericConnection.hci,头文件仅保留声明 + extern template 声明
    • 显式实例化集中在 GenericConnection.cpptcp::socket + ssl::stream<tcp::socket>
    • .hci 文件有 #ifndef HICAL_BUILDING_GENERIC_CONNECTION 防误包含守卫
  • HttpServer 编译防火墙
    • handleSession() + handleWebSocket()HttpServer.cpp 移至 HttpSessionImpl.cpp,隔离 Beast HTTP parser/serializer 和 WebSocket 重模板代码
    • 修改 HttpServer 配置逻辑不再触发 Beast 模板重编译
  • MetaJson 错误抛出优化
    • throw std::runtime_error(...) 从模板代码提取为 MetaJsonError.h/cpp 中的 [[noreturn]] 非模板函数(throwTypeMismatch / throwMissingField / throwParseError
    • 减少每个用户类型 HICAL_JSON 实例化的代码体积,改善 icache 利用率

Fixed

  • SyncAfterHandler 安全约束:禁止修改 body(仅允许 setHeader/setCookie),因 Content-Length 已由 prepare_payload() 固定,修改 body 会导致 HTTP Content-Length 不一致

Full Changelog: v2.5.1...v2.5.2

v2.5.1

08 May 10:19

Choose a tag to compare

Added

  • SyncMiddleware 快速路径(零协程帧中间件):
    • 新增 SyncBeforeHandler / SyncAfterHandler / SyncMiddlewareResult 类型(Middleware.h
    • 新增 MiddlewareEntry 统一存储结构(Async/Sync 标签联合)
    • MiddlewarePipeline 新增 3 个同步 use() 重载,RouteGroup 新增 2 个
    • buildOptimizedChain() 算法:连续 Sync 条目合并为单个协程帧,N 层同步中间件仅 1 次协程帧堆分配
  • MemoryPool::threadLocalPool() 公共方法,暴露 thread-local 无锁池资源指针

Changed

  • HttpServer 多 io_context 架构
    • ioContext_ 替换为 AsioEventLoop baseLoop_ + EventLoopPool ioPool_(1 Thread : 1 io_context)
    • acceptLoop() 去除 make_strand,round-robin 分发到 worker loop(单线程天然串行)
    • accept 后立即设置 TCP_NODELAY 减少 Nagle 延迟
    • stop() / gracefulStop() 改为停止所有 loop(baseLoop + ioPool)
  • handleSession() 请求级 PMR 池改为栈上 monotonic_buffer_resource + thread-local 无锁池作 upstream,消除 make_unique 堆分配和同步锁竞争
  • MiddlewarePipeline::build() / buildFor() 非 profiling 路径改用 buildOptimizedChain(entries_)
  • MiddlewarePipeline::size() 改为返回 entries_.size()(支持纯 Sync 中间件计数)
  • 新增 HttpServer::recommendedMaxConnections(availableMemoryMB) 静态方法:按 25KB/连接 估算并预留 30% 内存,上限 65535,供使用者根据机器内存自行设置 maxConnections(默认值仍为 10000)
  • PoolConfig::requestPoolInitialSize 默认值从 8192 降至 4096
  • handleSession() 主路径去除冗余 prepare_payload() 调用(已由 setBody() / setJsonBody() 内部完成)
  • RouteGroup 中间件预构建优化RouteGroup 同步分支接入 buildOptimizedChain(),组级 Sync 中间件同样享受零协程帧合并

Full Changelog: v2.5.0...v2.5.1

v2.5.0

04 May 17:00

Choose a tag to compare

Added

  • 日志系统(6 级日志,零开销设计):
    • Log.h/cppLogger 单例 + 6 级 LogLevel(Trace/Debug/Info/Warn/Error/Fatal),std::format 风格 API(HICAL_LOG_INFO("port={}", 8080))、流式 API(HICAL_LOG_INFO_STREAM << val)、条件宏(HICAL_LOG_INFO_IF)、结构化字段 API(HICAL_LOG_INFO_F),NDEBUG 下 TRACE 编译期消除,thread_local 时间戳/线程 ID 缓存,可配置 flush 级别,Fatal 自动 abort
    • LogRecord.h — 结构化日志条目(level/timestamp/threadId/file/line/message + boost::json::object fields + traceId)
    • LogFormatter.h/cpp — 格式化器接口 + TextFormatterthread_local 时间戳缓存)+ JsonFormatter(JSON Lines,UTC 时间戳)
    • LogSink.h/cpp — 可插拔输出后端接口 + StderrSink(fprintf)+ FileSink(同步 fwrite + LogFile 轮转)+ OStreamSink(线程安全 ostream 包装)
    • LogFile.h/cpp — 日志文件轮转引擎(按大小轮转默认 100MB、最大文件数限制、时间戳序列命名、严格文件名匹配清理)
    • AsyncFileSink.h/cpp — 异步双缓冲文件 Sink(std::jthread + stop_token 后台线程、4MB 前后缓冲交换、背压保护丢弃 + 计数、1 秒超时刷盘、优雅关闭含最终缓冲排空)
    • FixedBuffer.h — 栈上固定缓冲区模板(默认 4KB),std::to_chars 整数/浮点格式化,溢出自动 fallback 到堆
    • LogChannel.h/cpp — 命名日志通道(独立 level/formatter/sinks),LogChannelRegistryshared_mutex 读多写少),HICAL_LOG_TO 通道路由宏
    • LogMiddleware.h/cpp — 洋葱模型日志中间件(OpenSSL RAND_bytes 128 位 trace-id 自动生成,结构化访问日志到命名通道)
    • LogAdmin.h/cpp — 动态日志级别管理端点(GET /admin/log-level 查询 + PUT /admin/log-level 运行时调整)
    • 9 个测试文件(97 个用例):test_log / test_log_ndebug / test_fixed_buffer / test_log_file / test_async_file_sink / test_log_formatter / test_log_channel / test_log_middleware / test_log_admin
  • OpenAPI 3.0 自动生成模块HICAL_WITH_OPENAPI=ON,默认开启,零新依赖):
    • OpenApiSchema.h — 从 HICAL_JSON 宏自动生成 JSON Schema(基本类型/vector/嵌套结构体/$ref),HICAL_SCHEMA_NAME 注册类型名,collectSchemas<T>() 递归收集
    • OpenApiRegistry.h/cpp — 路由元数据注册表(HICAL_API() 综合标注宏 + builder::* 辅助函数、HICAL_ROUTES_WITH_API() 增强版路由收集、registerRoutesWithOpenApi() 同时注册路由和元数据)
    • OpenApiDocument.h/cpp — 文档组装(惰性生成 + 缓存、自动路径参数提取、同路径不同 method 合并为同一 Path Item)
    • OpenApiEndpoint.hserveOpenApi() 一键注册 /openapi.json + /docs(Swagger UI CDN),boost::json::serialize() 安全转义防 JS 注入
    • 1 个测试文件(35 个用例):test_openapi
    • 1 个示例:examples/openapi_server.cpp

Full Changelog: v2.4.0...v2.5.0

v2.4.0

01 May 14:39

Choose a tag to compare

Added

  • CORS 中间件
    • Cors.hmakeCorsMiddleware(CorsOptions{...}),支持 Origin 通配符/精确匹配、Preflight OPTIONS 自动响应、Vary: Origin 缓存提示、凭证模式下禁止通配符安全校验、可配置 maxAge
  • 路由组(Route Group)
    • RouteGroup.h/cpprouter.group("/api/v1") 前缀分组,支持组级中间件继承、多层嵌套、镜像 Router API(get/post/put/del/route)
  • HTTP 核心增强
    • HttpRequest 新增查询参数解析 API(queryParam()/queryParams())和表单参数解析 API(formParam()/formParams()
    • HttpResponse 新增 redirect() 便捷方法
    • HttpServer 新增全局错误处理器 setErrorHandler(),优雅关闭 shutdown() 支持
    • 7 个测试文件:test_query_params / test_form_params / test_redirect / test_cors / test_route_group / test_error_handler / test_graceful_shutdown

Full Changelog: v2.3.0...v2.4.0