Chi是网关路由层的合理默认起点,必须用chi.NewRouter()初始化接口;中间件须在路由注册前调用Use;路径参数只能用chi.URLParam提取;嵌套路由必须用Group()而非字符串拼接。

Chi 不是“可选配置项”,而是网关路由层的合理默认起点——它不侵入业务逻辑、不绑定框架、中间件链清晰,且能直接对接 http.Handler 接口。
chi.Router 必须用 chi.NewRouter() 初始化,否则 panic
Chi 的 chi.Router 是接口类型,不能零值构造。写 var r chi.Router 或 r := chi.Router{} 都会在调用 Use、Get 时触发 panic: nil pointer dereference。
-
chi.NewRouter()返回的是内部*mux实例指针,所有方法都绑定在其上 - 网关主路由必须这样初始化:
r := chi.NewRouter(),之后才能挂载中间件和子路由 - 若需复用某组路由逻辑(比如统一鉴权的用户服务路由),应封装为函数返回
chi.Router,而非试图“构造”接口
中间件顺序错位会导致路由完全失效
Chi 的中间件注册是静态绑定:只对 Use() 调用之后注册的路由生效。网关中常见的日志、鉴权、限流等全局中间件,必须放在所有 Mount 和 Get/Post 之前。
- 错误写法:
r.Get("/health", h); r.Use(mw)→h完全收不到中间件 - 正确顺序:
r.Use(logger, auth, rateLimit); r.Mount("/api/users", userRouter) - 注意:
chi.With()创建的是带新中间件栈的子路由器,其中间件不会透传给Mount或Group内部注册的路由
路径参数必须用 chi.URLParam(r, "name") 提取
网关转发前常需提取路径参数做服务发现或权限校验,但 Chi 不会把路径参数塞进 r.URL.Query() ——这是新手最常踩的静默坑。
立即学习“go语言免费学习笔记(深入)”;
-
/users/{id}/profile?token=abc中,id是路径参数,token是查询参数 - 必须用
chi.URLParam(r, "id")获取id;r.URL.Query().Get("id")永远为空 - 参数名拼错(如路由定义为
{userID}却写chi.URLParam(r, "id"))→ 返回空字符串,不 panic,但后续逻辑可能出错 - 安全写法:
if id := chi.URLParam(r, "id"); id != "" { /* 转发或校验 */ }
嵌套路由必须用 Group(),别拼接字符串前缀
网关常按服务划分路由域(如 /api/v1/users、/api/v1/orders),手动拼接路径前缀看似简单,实则破坏中间件作用域和调试能力。
- 错误做法:
userRouter := chi.NewRouter(); userRouter.Get("api/v1/users", h)→ 中间件无法统一注入,chi.Doc无法生成层级文档 - 正确做法:
apiV1 := r.Group("/api/v1"); apiV1.Mount("/users", userRouter); apiV1.Mount("/orders", orderRouter) -
Group()返回的子路由器继承父路由中间件栈,且支持独立Use(),不影响其他分组 - 若需反向代理(如
userProxy),记得用通配符:userRouter.Handle("/*", userProxy),否则子路径匹配失败
Chi 在网关场景里真正的复杂点不在语法,而在中间件作用域与路径参数提取的隐式契约——它不报错,但一旦错位或误用,问题会藏在请求链路深处,直到转发失败或权限绕过才暴露。



















