中间件执行顺序严格由app.Use()注册顺序决定,先注册的先执行;写响应后必须立即调用ctx.StopExecution(),否则控制流继续导致重复响应或panic。

中间件执行顺序必须靠注册顺序控制
中间件不是按名称或类型自动排序的,app.Use() 的调用顺序就是实际执行顺序。先 Use 的中间件最先拿到请求,也最先有机会调用 ctx.Next() 把控制权往下传;如果某个中间件没调 ctx.Next(),后面的中间件和最终 handler 就完全不会执行。
常见错误现象:在日志中间件之后注册了 JWT 验证中间件,但日志里始终看不到请求记录——因为 JWT 中间件验证失败后直接 ctx.StatusCode(401) + ctx.StopExecution(),没调 ctx.Next(),日志中间件虽已注册,但根本没被触发。
使用场景:典型链式流程如 Recovery → Logger → CORS → Auth → Handler,其中 Recovery 必须最前(捕获 panic),Auth 必须在业务 handler 前(否则鉴权失效)。
- 多个中间件注册时,别用变量赋值再批量
Use,容易因变量复用导致顺序错乱 - 路由组内单独加的中间件(如
app.Party("/admin").Use(auth))会叠加在全局中间件之后,但只作用于该组下的路由 - 用
app.UseGlobal()注册的中间件会作用于所有路由(包括Party子路由),但它不改变Use的原始顺序语义
中间件里写响应后必须立刻 ctx.StopExecution()
Iris 不会自动阻止后续逻辑执行。一旦你在中间件里写了 ctx.JSON(401, ...) 或 ctx.Redirect(...),但忘了调 ctx.StopExecution(),控制流仍会继续走到下一个中间件甚至最终 handler,造成重复响应、状态码冲突或 panic(比如 handler 又尝试写 body)。
典型踩坑点:JWT 解析失败后只写 ctx.JSON(401, iris.Map{"error": "invalid token"}),末尾还留着 ctx.Next() —— 这会导致 401 响应体发出去后,程序继续执行业务逻辑,可能查数据库、改状态,甚至再发一次 200 响应。
- 写响应后立即跟
ctx.StopExecution(),且确保ctx.Next()在 if 分支外不被执行 - 不要依赖 “写了状态码就自动终止” —— Iris 没这层保护
- 调试时可在每个中间件开头加
app.Logger().Infof("in %s", "middleware-name"),快速确认是否被跳过或重复执行
路由组中间件和全局中间件的叠加规则
app.Party("/api").Use(mw1) 注册的中间件,只对 /api/* 下的路由生效;它会在全局中间件之后、该路由对应 handler 之前执行。但注意:如果全局中间件已经 StopExecution(),路由组中间件根本不会运行。
使用场景:管理后台需要额外权限校验(adminAuth),而 API 接口需要频率限制(rateLimiter),两者互不干扰,靠分组隔离最干净。
- 同一个中间件实例不能被多次
Use到不同组,否则状态(如计数器)会被共享,引发并发问题;需每次新建实例或用工厂函数 -
Party支持链式注册:app.Party("/v1").Use(auth).Use(log).Get("/users", handler),比分开写更直观 - 若想让某个路由跳过某中间件,目前 Iris 没有“跳过指定中间件”的机制,只能拆成不同
Party或在中间件内部用路径判断if ctx.Path() != "/health"手动绕过
ctx.Next() 不是“继续”,而是“移交控制权”
ctx.Next() 的语义非常轻量:它只是把当前上下文交给下一个中间件或最终 handler,并不阻断当前函数剩余代码。很多人误以为调了 Next() 就等于“return”,结果在它后面又写日志、改 header,甚至二次写响应。
性能影响:多余的 ctx.Next() 调用本身开销极小,但逻辑错乱带来的副作用(如重复 DB 查询、并发写冲突)代价很高。
- 推荐模式:用
if !valid { ctx.StopExecution(); return }显式退出,而不是靠Next()隐式流转 - 不要在
Next()后面放任何可能改变响应状态的代码,除非你明确知道前面的 handler 绝不会写响应 - 调试时打印
ctx.Response().StatusCode()和ctx.Response().Written(),能快速发现是否已被写过响应
StopExecution() 和 Next() 的配对关系。最容易被忽略的是:**中间件里写响应后不 StopExecution(),程序不会报错,但行为完全不可控。**


















