单个路由中间件必须位于handler之前且按执行顺序从左到右排列,gin仅通过位置而非参数类型识别中间件;漏写c.next()将拦截后续流程,需用c.abort()中断;它仅对当前路径生效,不继承路由组中间件。

单个路由中间件必须写在 handler 前面
调用 r.GET()、r.POST() 等方法时,中间件函数要放在最后一个业务 handler 之前,且按执行顺序从左到右排列。Gin 不会识别参数名或类型自动区分中间件和 handler,只靠位置判断。
-
r.GET("/user", authMiddleware(), logMiddleware(), userHandler):三个函数都会被当作中间件执行,userHandler是链中最后一个处理单元 - 错误写法:
r.GET("/user", userHandler, authMiddleware())——userHandler先执行,后续中间件不会触发 - 中间件函数必须是
gin.HandlerFunc类型;闭包返回值若未显式转为该类型(如漏掉return func(c *gin.Context) { ... }),会导致编译失败或 panic
中间件里不写 c.Next() 就等于拦截整个链
单个路由中间件和全局中间件一样,依赖 c.Next() 控制流程走向。它不是“调用下一个函数”,而是让 Gin 继续执行链表中的后续项(包括其他中间件和最终 handler)。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 漏写
c.Next():请求停在当前中间件,后续所有逻辑(含 handler)都不执行 - 写在开头:前置校验后立刻放行,适合鉴权通过即透传的场景
- 写在末尾:变成纯后置操作,比如记录响应耗时或清理资源,但无法影响 handler 执行结果
- 想中断流程(如 token 失效),必须调用
c.Abort()或c.AbortWithStatusJSON(),之后c.Next()不再生效
别把单路由中间件和路由组中间件混用
单路由中间件只对当前注册的那一条路径生效,和路由组无关。常见误操作是以为给 /api 组加了中间件,子路径就自动继承,结果发现 /api/user 没走鉴权。
- 正确做法:每个需要保护的接口单独加中间件,或统一用
Group().Use()管理 - 错误模式:
api := r.Group("/api"); api.Use(auth); r.GET("/api/user", userHandler)—— 这里r.GET注册在根路由,不经过api组,auth 完全无效 - 更隐蔽的坑:
r.Group("/api").Use(auth).GET("/user", handler)——Group()返回新分组,Use()作用于该分组,但链式调用后未保存引用,GET()实际注册到根路由
调试时注意日志输出顺序和 panic 行为
中间件执行顺序是栈式(LIFO),但日志打印顺序是线性。如果多个中间件都打日志,容易误判执行流;而 panic 发生时,c.Next() 后的代码仍会执行,可能掩盖真实错误点。
- 建议在中间件开头打
fmt.Println("→ m1 enter"),结尾打fmt.Println("← m1 exit"),观察进出是否成对 - 若 handler panic,
Recovery()中间件会捕获并返回 500,但前提是它已通过r.Use()注册为全局中间件;单路由中间件里没加Recovery,panic 会直接崩掉请求 - 测试单路由中间件最简单方式:写一个只调用
c.Abort()的中间件,看接口是否真不返回数据










