chi.router 必须用 chi.newrouter() 初始化,直接声明接口变量会导致 nil panic;中间件需在路由注册前调用 use;路径参数须用 chi.urlparam 提取,不可用 r.url.query();嵌套路由应使用 group 或 mount,避免手动拼接。

chi.Router 必须用 chi.NewRouter() 初始化
直接写 router := chi.Router{} 或 var r chi.Router 会导致运行时 panic:nil pointer dereference。因为 chi.Router 是接口类型,不是结构体;它背后依赖内部 *mux 实例,只有 chi.NewRouter() 才能返回一个完整、可调用方法的实现。
常见错误:在初始化后立刻调用 router.Use() 或 router.Get() 却崩溃——八成是这里漏了 NewRouter()。
- 正确写法:
router := chi.NewRouter(),之后再注册中间件和路由 - 想复用路由逻辑?封装成函数返回
chi.Router,别试图“构造”接口值 - 如果用了 IDE 自动补全提示
chi.Router{},务必手动删掉,换为工厂函数
中间件必须在路由注册前调用 router.Use()
router.Use() 是静态绑定:只对它之后注册的路由生效。顺序错位是线上 panic 的高频原因,尤其当 handler 里尝试从 r.Context().Value() 取值却得到 nil 时。
典型陷阱:router.Get("/api/user", h) 写在 router.Use(mw) 前面 → h 完全收不到中间件注入的数据。
- 全局中间件(如
middleware.Logger、middleware.Recoverer、JWT 验证)必须放在所有Get/Post之前 -
chi.With()返回新路由实例,它的中间件不透传给Mount或Group内部注册的路由 - 用
Group()分模块时,要么在父路由统一Use后再Mount,要么每个Group单独调用Use
路径参数只能用 chi.URLParam(r, "name") 提取
/user/{id}/profile?format=json 中,id 是路径参数,format 是查询参数。Chi **不会** 把路径参数塞进 r.URL.Query(),新手常在这里卡住,查 r.URL.Query().Get("id") 永远返回空字符串。
chi.URLParam(r, "id") 从路由匹配结果中读取,安全但不自动校验非空——拼错参数名(比如路由定义是 {userID} 却写 chi.URLParam(r, "id"))只会返回空字符串,不 panic,但业务可能静默失败。
- 必须用
chi.URLParam(r, "name"),别碰r.URL.Query()提路径参数 - 推荐防御写法:
if id := chi.URLParam(r, "id"); id != "" { /* 处理 */ } - 正则约束路由如
/articles/{slug:[a-z0-9-]+}仍用同一方式提取,无需额外解析
嵌套路由必须用 Group() 或 Mount(),不能拼接字符串
手动拼接前缀(如 "api/v1" + "/users")看似简单,实则破坏中间件作用域、路由树结构,且调试时 chi.Doc 无法正确输出分组路径。
Group() 返回子 chi.Router,继承父路由中间件栈;Mount() 用于挂载独立子路由(注意:子路由需显式 Mount,否则根本不会被父路由器识别)。
-
Group()适合同前缀、同中间件策略的路由集合(如/admin/*) -
Mount("/api", subR)第一个参数必须以/开头、不以/结尾;subR内写的路径是相对的 - 别把
Group和Mount混用——Chi 没有Group方法?不对,Group是存在的,但它是chi.Router的方法,不是第三方扩展
最易被忽略的一点:Chi 的所有能力都建立在标准 net/http 接口之上,没有自定义 Handler 类型或上下文包装。这意味着你随时可以切回原生 http.ServeMux,或混用社区任意 func(http.Handler) http.Handler 中间件——但前提是,你得先让 chi.NewRouter() 跑起来,且中间件顺序、参数提取、嵌套方式都踩对节奏。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











