Custom 旋钮体系:非预设字段的开放世界
xs.json 里没被宿主预设的字段去哪了?——原样进 Custom,留给应用自己读。这个"开放世界"同时承载了 http 驱动的请求限额。
本章导读
9.1 引入
配置系统迟早会遇到一个问题:框架预设的字段不够用。常见解法是框架不断加字段,结果配置项膨胀、语义漂移。XServer 的解法是划一条清晰的线:预设字段描述宿主装配事实(端口、协议、证书),其余一切字段不弹出、不校验、原样保留——它们在运行期以 xvalue 树的形式挂在 server->Custom、host->Custom 与 xsConfigRoot() 上,由应用决定含义与校验。
9.2 Custom 的读取模型
/* 1. 根级 Custom:xsConfigRoot 返回 retained xvalue,需 Release */
xvalue* pRoot = xsConfigRoot();
xvalue* pMy = xrtValueObjectGet(pRoot, "my_app");
xrtValueRelease(pRoot);
/* 2/3. server / host 级:视图字段直接挂在信息结构上(借用)*/
xvalue* pSrvCustom = pReq->server->Custom;
xvalue* pHostCustom = pReq->host->Custom;
刚才发生了什么:根级要 Release(你自己持有了引用);server/host 级的 Custom 是视图字段——回调内读取安全,保存需遵守第 3 章的所有权规则。
严格解析工具
demo 的 stream 模块提供了 XS_CustomReadUInt:从 Custom 树读一个严格非负整数——类型不对、值为负都返回失败而不是猜一个默认值。读旋钮请用它,别用宽松转换。
9.3 六个请求限额旋钮
Custom 开放世界最重要的"住户"是 http/ws 驱动消费的请求限额(写在 server 级,应用亦可读):
| 旋钮 | 默认 | 超限行为 |
|---|---|---|
header_limit | — | 431 Request Header Fields Too Large |
path_limit | 2048 | 414 URI Too Long |
body_limit | — | 413 Content Too Large |
idle_timeout | — | 静默关闭连接(http/ws/tcp 通用) |
ws_message_limit | — | close code 1009 |
ws_protocol | — | 握手 400(要求子协议不匹配) |
为什么这些是 Custom 而不是预设字段?因为它们描述的是"这台服务对请求的态度"——属于部署策略而非装配事实;而且类型校验发生在使用侧(如 ws_protocol 启动时校验合法性),保持了"谁消费谁校验"的一致性。
9.4 契约
- 所有权线:xsConfigRoot 是 retained(配对 Release);server/host Custom 是借用视图。
- 校验线:Custom 字段宿主不校验——应用读取时必须严格解析(XS_CustomReadUint 模式),拒绝宽松转换。
- 命名线:用带应用前缀的键名(my_app.*),避免与 http 驱动的惯例旋钮(header_limit 等)撞名。
常见错误
- 症状
- 每代脚本泄漏一个 xvalue 引用;内存报告里根对象计数递增。
- 原因
- 文档契约:返回 retained,必须 xrtValueRelease——第 3 章所有权规则的标准应用。
- 症状
- 配置写 "body_limt"(拼错),应用拿到默认值 0,行为异常但无报错。
- 原因
- 用"取不到就当 0"的宽松读法。Custom 没有宿主校验,拼错只能靠应用侧严格读法暴露。
uint32 n = 0;
GetValue(pCustom, "body_limit", &n);
/* 取不到静默为 0 *//* 严格读:取不到就报配置错误 */编程练习
在 xs.json 根级加 "my_app": {"greeting": "hi"},脚本 ServiceInit 里读出并打印。
给 demo 配 body_limit=100,分别发送 99 / 101 字节 POST,记录状态码差异;再配 path_limit=50 发长路径。
写一个 modules/knobs.h:声明式定义应用旋钮(键/类型/默认/是否必需),Init 时统一严格校验并报出全部缺失项。
小结
| 要点 | 结论 |
|---|---|
| Custom 定义 | 非预设字段原样保留,宿主不弹出不校验 |
| 读取入口 | xsConfigRoot(retained)/ server->Custom / host->Custom(借用) |
| 请求限额 | header/path/body_limit + idle_timeout + ws 两项,超限 431/414/413/关连/1009 |
| 读法纪律 | 严格解析(XS_CustomReadUInt 模式),键名带应用前缀 |
- xrt 参考 · value — Custom 树的访问 API 全集