xs.json 全解 · 主机级与 vhost
一个 server 装多个站点:host_default 兜底一切未命中的请求,hosts[] 按域名精确分流。本章讲清路由的三个来源与证书的按 host 分发。
本章导读
8.1 引入
单机多站是服务器的常态需求:主站、API、管理后台、若干客户站点共用一个进程。XServer 的模型是server(端点)× host(站点)两级:一个 server 监听端口,收到的请求按"它是给哪个站点的"路由到 host;每个 host 有独立的静态根、脚本、证书。
8.2 主机级字段
| 字段 | 约束 | 说明 |
|---|---|---|
name | server 内唯一、非空 | 主机名;重复 / 空都 fail-fast |
host | 分号分隔域名 | http/ws 的启用 vhost 必填非空;如 "a.com;www.a.com" |
path | 目录须存在 | 静态根;缺失 fail-fast |
devlang / devfile | — | c / static / 自定;static 则 devfile 可空 |
tls_ca / tls_cert / tls_key | PEM 路径 | host 级证书 → SNI 表数据源(见 8.4) |
一个域名只能绑在一个 host 上(重复绑定 fail-fast);一个 host 可绑多个域名(分号分隔,大小写不敏感按域规则处理)。
8.3 路由三来源
HTTP 请求里"目标主机"可能出现在三个位置,XServer 依次取用:
| 来源 | 形态 | 典型场景 |
|---|---|---|
| Host 头 | Host: a.com:8080 | 日常绝大多数请求(端口后缀被剥离) |
| absolute-form | GET http://a.com/x HTTP/1.1 | 代理型客户端 |
| authority-form | CONNECT a.com:443 | 隧道请求 |
- HTTP/1.1 强制 Host:缺失或重复都按协议错误处理(400)——这是行为正确性,不是可选校验
- 未命中任何 hosts[] → 回落 host_default;keep-alive 连接内切换 Host 也能逐请求正确路由
- TLS 端点上的身份选择发生在握手里(SNI,见下节),HTTP 层路由在解密后进行——两层一致
8.4 host 级证书与 SNI
每个 http/ws host 可以有自己的 tls_ca/tls_cert/tls_key。装配时它们进入 SNI 表;TLS 握手中客户端在 ClientHello 里带上要访问的域名(SNI),服务端据此选出对应证书——域名与证书的匹配在握手期完成,HTTP 请求还没开始。服务端 Cookie 机制把 ClientHello 的身份选择与 Accept 绑定到同一代,避免握手跨代的竞态。
8.5 契约
- 路由线:Host 三来源 → hosts[] 精确匹配 → host_default 回落;HTTP/1.1 无 Host 即 400。
- 证书线:host 级证书按 SNI 分发;未配置证书的 host 在 TLS 端点上无法完成握手身份选择。
- 脚本线:每个 devlang=c 的 host 一份独立脚本运行时——重载以 host 所属 server 的完整 generation 为发布单元。
常见错误
- 症状
- 配了 "api.com" 期望 "www.api.com" 也命中,结果进了 default。
- 原因
- host 绑定是精确匹配(分号列表逐个比对),不做通配与前缀。
"host": "api.com"
/* 期望 www.api.com 也进来 */"host": "api.com;www.api.com"- 症状
- 启动失败:http/ws 启用 vhost 的 host 字段必填非空。
- 原因
- 空域名的 vhost 没有路由意义——想"全收"应该用 host_default,而不是空 host。
编程练习
单 server 配 host_default(站点甲)+ hosts[](站点乙,绑 test.local),两个 wwwroot 各放不同 index.html。
用 curl 的 --resolve 与 absolute-form(curl -x http://127.0.0.1:8080 http://test.local/代理形态)分别触发 Host 头与 absolute-form 两种路由来源。
写脚本在一条 keep-alive 连接上连续发两个不同 Host 的请求,验证逐请求路由正确。
小结
| 要点 | 结论 |
|---|---|
| 两级模型 | server = 端点;host = 站点(静态根/脚本/证书) |
| 路由 | Host 头 / absolute-form / authority-form 三来源,精确匹配 |
| 回落 | host_default 恒存在,未命中即进它 |
| 证书 | host 级 → SNI 表,握手期分发;可热替换 |
- xrt 参考 · tls_server — SNI 选择器与服务端 Cookie 的底层实现
- xrt 参考 · http1 — Host 头解析与 absolute-form 的协议细节