fiber中host路由匹配必须用app.host,不能靠app.get拦截host头;app.host支持泛域名如*.example.com(仅一级),需配合c.hostname()提取子域名,strictrouting须显式开启以防尾斜杠歧义,tls终止应由nginx/traefik等反向代理完成。

Host路由匹配必须用 app.Host,不能靠 app.Get 拦 Host 头
Fiber 的 app.Get 等方法只匹配路径(Path),对 Host 头完全无感知。你写 app.Get("/user", ...) 并在 handler 里手动读 c.Host() 判断子域名,等于把路由逻辑后移到业务层——这会破坏 Fiber 的 Radix 树路由性能优势,且无法实现真正的“动态子域名隔离”。正确入口是 app.Host,它底层注册的是 Host 专用的 trie 节点,匹配发生在请求解析早期,不消耗 handler 执行周期。
常见错误现象:本地 curl -H "Host: api.example.com" http://localhost:3000/ 能跑通,但部署到 Nginx 后所有子域名都落到同一个 handler,因为 Nginx 默认不透传 Host 头,或配置了 proxy_set_header Host $host; 却漏了 $request_uri 导致路径被重写。
-
app.Host("*.example.com")支持通配符,但仅限一级(api.example.com匹配,dev.api.example.com不匹配) - 多级子域名必须显式列出:
app.Host("api.example.com", "admin.example.com", "shop.example.com") - 根域名和子域名冲突时,Fiber 按注册顺序匹配,先注册的优先;建议把泛匹配
"*.example.com"放最后
动态提取子域名要用 c.Hostname(),不是 c.Host()
c.Host() 返回原始 Host 字符串(含端口,如 api.example.com:3000),而 c.Hostname() 自动剥离端口并做标准化(返回 api.example.com)。这是关键区别——如果你用 c.Host() 做字符串切分,遇到 HTTPS 重定向或非标端口就会出错。
使用场景:SaaS 多租户系统,每个租户一个子域名(acme.example.com),需从 Host 中提取 acme 作为 tenant_id 查询数据库。
- 安全写法:
host := c.Hostname(); parts := strings.Split(host, "."); if len(parts) >= 3 { tenant := parts[0] } - 别用正则匹配
^([a-z0-9]+)\.example\.com$,Fiber 不校验 Host 合法性,恶意请求如evil..example.com会导致parts[0]为空字符串 - 若需支持国际化域名(IDN),得先调
idna.ToASCII(host)转码,否则大小写和连字符处理不一致
泛域名 + 路由参数组合容易踩空,必须显式声明 StrictRouting
当你写 app.Host("*.example.com").Get("/users/:id", handler),Fiber 默认允许 /users/123/(尾部斜杠)也匹配——但 Host 泛匹配下,这个行为会引发歧义:如果 api.example.com 和 admin.example.com 共享同一组路由,/users/123/ 在 admin 域下可能本意是访问目录列表,却被当成带斜杠的 ID 参数。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
根本原因是 app.Host 创建的子应用默认继承父 app 的 StrictRouting 配置,而 Fiber v3 默认值为 false。线上必须显式关掉宽松匹配:
- 全局设置:
fiber.New(fiber.Config{StrictRouting: true}) - 子 Host 应用单独设:
app.Host("*.example.com", fiber.Config{StrictRouting: true}) - 不设的话,
/users/123和/users/123/会被视为两个不同路由,缓存、监控指标都会分裂
泛域名路由无法直接绑定 TLS,得靠反向代理终止 SSL
Fiber 本身不支持 SNI(Server Name Indication)动态加载证书,app.ListenTLS 只能指定单个证书文件。这意味着你无法让 app.Host("*.example.com") 自动根据请求 Host 选择对应域名的证书。
生产唯一可行路径是:用 Nginx 或 Traefik 做 TLS 终结,把解密后的 HTTP 请求(带正确 Host 头)转发给 Fiber;Fiber 只处理纯 HTTP 流量。否则你会陷入证书管理泥潭——每次新增子域名都要重启 Fiber 进程、热更新证书在 fasthttp 层极不稳定、Let’s Encrypt ACME 协议集成复杂度远超收益。
容易被忽略的细节:
- Nginx 配置中必须加
proxy_set_header Host $host;,不能写成$http_host,否则带端口的 Host 会污染 Fiber 的c.Hostname() - Traefik 的
rule: Host(`{subdomain:[a-z0-9]+}.example.com`)是路由规则,不是证书绑定;证书仍需在 entryPoints 层统一配置 - 本地开发用
mkcert生成泛域名证书(*.example.test)可绕过浏览器警告,但该证书不能用于生产环境










