第 14 章 / 共 51 章
卷三 · 协议开发

HTTP 基础:视图结构与三态返回

RequestProc 收到的不是包装对象,而是一组"可以直接动手"的 xrt 原生指针。本章把这张视图地图画完整——之后四章都在这张地图上作业。

本章导读

站位:卷三的地图章。ch15(响应)、ch16(请求体)、ch17(路由)分别展开视图的不同侧面;本章先建立整体认知与两条铁律(借用、三态)。

14.1 引入

写 HTTP 业务需要三种东西:知道请求是什么(方法、路径、头、体)、知道往哪写响应(传输层)、知道处理完之后谁接管。多数框架把三者揉进一个 Request/Response 对象,用抽象换便利;XServer 把三者拆开直接给你——XS_HttpReq 的六个字段就是这三样东西的地址。

14.2 XS_HttpReq 逐字段

XS_HttpReq(xsbase.h 原文)出处:src/sdk/xsbase.h
typedef struct {
    xnetstream*       tcp;    /* 与 tls 二选一非空:传输层裸指针   */
    xtlsstream*       tls;    /*   可直接使用 xrt 全套流/发送 API  */
    const xhttp1head* head;   /* 含 MethodCode;视图回调内有效     */
    xhttp1body*       body;   /* 分帧状态机:定长 / chunked / 关闭 */
    const XS_HostInfo*  host;
    XS_ServerInfo*    server;
} XS_HttpReq;
字段用途本 章 用 法
tcp / tls响应出口发送响应字节(ch15 展开)
head请求身份MethodCode、路径、字段视图(本章 14.3)
body请求体增量读取(ch16 展开)
host / server归属读拓扑信息、Custom 旋钮

为什么没有 Response 字段?——因为响应不是对象,是你写进传输层的字节流。这正是"零包装"的彻底之处:没有隐藏的响应缓冲,也就没有"框架什么时候 flush"这类问题。

14.3 请求头读取

方法、路径与字段
static XS_RequestResult RequestProc(XS_HttpReq* pReq)
{
    /* 方法:位掩码,既是单方法也是集合元素(ref-enums)*/
    if ( pReq->head->MethodCode == XHTTP_METHOD_GET ) { ... }

    /* 路径与字段视图:xstrview = 指针 + 长度,回调内有效 */
    /* 具体取值 API(字段查找 / 路径分解)见 xrt · http1 参考 */
    return XS_FALLBACK;
}

两条读头铁律:第一,head 的字段视图只在本回调栈内有效——XServer 在 PinHead 阶段拷贝了请求头防止 ring-buffer 复用,但换代/请求结束后仍然失效;第二,比较路径不要用 C 字符串函数——视图带长度,按长度比较(xrtStrView 系工具)。

14.4 调用时机与线程

连接建立 → 请求头解析完成 → RequestProc(worker 线程,可并发) │ ┌────────────────────┼────────────────────┐ ▼ XS_OK ▼ XS_FALLBACK ▼ XS_TAKEOVER 驱动消费 body 余量 GET/HEAD → 静态层 应用接管连接 继续 keep-alive 循环 其余 → 404 (ch25)
  • 每请求一次;keep-alive 连接上逐请求调用
  • workers 并发——RequestProc 必须可重入(无跨请求可变静态状态,或自行加锁)
  • 驱动与脚本之间有字节消费同步校验:你声明的消费量与线路实际不符即断连——把脚本当不可信边界对待

14.5 契约

  • 借用线:六个字段全部回调内有效;值可拷贝带走,指针不行。
  • 三态线:XS_OK 前必须写完响应;写过一个字节就不能 FALLBACK;TAKEOVER 后驱动撤出。
  • 并发线:RequestProc 在 workers 上并发执行,可重入是硬要求。

常见错误

用 strcmp 比较路径视图
症状
偶发路径判断错误,尤其路径含查询串或非零结尾缓冲。
原因
xstrview 不是 C 字符串——它可能不带 NUL 终止,长度才是权威。
✗ 错误
if ( strcmp(pPath, "/api") == 0 )
✓ 正确
/* 按视图长度比较(xrtStrView 工具)*/
RequestProc 里放了跨请求可变静态
症状
并发下计数错乱、偶发崩溃。
原因
忘了 workers 并发——静态变量被多个请求同时读写。

编程练习

基础方法分诊台

写 RequestProc:GET 打印 "GET"、POST 打印 "POST",其余返回 XS_FALLBACK。

验收:三种方法各测一次,日志与回落行为符合预期。
进阶并发安全计数

统计已处理请求数(提示:原子操作,xrtAtomic 族)。

验收:压测 1 万请求后计数 = 1 万,无丢失无撕裂。
挑战视图生命周期实证

把 head 的某个视图指针存全局,下一个请求再读——观察并解释现象;然后改成回调内拷贝。

验收:能按第 3 章的代/借用模型解释崩溃或错乱的原因。

小结

要点结论
视图结构tcp/tls(出口)+ head(身份)+ body(体)+ host/server(归属)
无 Response 对象响应是写进传输层的字节流(ch15)
读头铁律视图回调内有效;按长度比较,不当 C 字符串
并发workers 可重入;消费量与线路同步校验
xrt 延伸阅读