中间件注册顺序即执行顺序,Iris 不采用优先级数字或权重配置:app.Use()、party.Use()、路由参数中间件按声明先后线性串联执行;UseGlobal() 总最先执行;ctx.Next() 必须在条件判断后且仅调用一次,错误分支需配 ctx.StopExecution()。

中间件注册顺序就是执行顺序
Iris 不搞“优先级数字”或“权重配置”,app.Use()、party.Use()、路由参数里传的中间件,谁先注册/声明,谁就先执行。没有隐式覆盖,也没有自动排序逻辑。
常见错误是以为子分组 Use() 会重置链路,结果 api.Use(m1) 后再 v1 := api.Party("/v1"); v1.Use(m2),请求 /v1/user 仍会走 m1 → m2 → handler,不是只走 m2。
-
app.UseGlobal()总是最先执行(已标记弃用,但行为不变) - 多个
app.Use()按调用顺序串行执行 - 路由级中间件(如
app.Get("/x", m1, m2, h))在全局和分组之后、handler 之前执行 -
party.Use()是追加,不是替换——父分组的中间件不会消失
ctx.Next() 的位置决定流程是否继续
中间件函数里不写 ctx.Next(),后续所有中间件和最终 handler 都不会执行;写两次,可能 panic 或重复写响应;写在错误分支里没加 ctx.StopExecution(),会导致鉴权失败后业务逻辑照常跑。
典型反模式:
立即学习“go语言免费学习笔记(深入)”;
if token == "" {
ctx.StatusCode(401)
ctx.JSON(map[string]string{"error": "missing token"})
ctx.Next() // ❌ 错误:这里不该调 Next()
}
ctx.Next() // ✅ 正确位置:仅当确定要继续时才调
- 所有提前终止逻辑(校验失败、权限拒绝)之后,必须跟
ctx.StopExecution() -
ctx.Next()应放在所有条件判断之后,且只出现一次 - 不要用
defer ctx.Next()—— Iris 不支持 defer 控制流转
全局、分组、路由三级中间件怎么叠加
三者作用域互不干扰,但执行流是线性串联的:UseGlobal() → app.Use() → party.Use() → 路由参数中间件 → handler。你不能靠“不注册”来跳过某一层,只能靠条件判断绕过逻辑。
比如想让 /health 跳过日志中间件,不能删掉 app.Use(logger),而得在 logger 函数里加判断:
func logger(ctx iris.Context) {
path := ctx.Path()
if path == "/health" || path == "/metrics" {
ctx.Next()
return
}
// 实际日志逻辑...
ctx.Next()
}
-
app.Use()注册的中间件对所有匹配路由生效(包括 404) -
party.Use()只影响该分组及其子分组注册的路由 - 路由级中间件(参数形式)只对该条路由生效,且顺序即执行顺序
- 若需完全隔离,应建独立
Party,而非依赖“跳过”逻辑
OPTIONS 预检请求为什么总进不了中间件
因为 Iris 不自动捕获预检请求。即使你写了 app.Use(cors),如果没显式注册 app.Options("/api/*", ...) 或对应路径的 OPTIONS 路由,请求根本不会匹配到任何路由,中间件自然不触发。
正确做法是:对目标路径范围,同时做两件事:
- 注册
OPTIONS路由(哪怕空 handler):api.Options("*", func(ctx iris.Context) {}) - 在中间件里设置 CORS 头,并校验
Origin是否在白名单中 - 注意:
Access-Control-Allow-Credentials: "true"时,Access-Control-Allow-Origin不能是"*"
最容易被忽略的是:CORS 中间件里的头设置,只有在 OPTIONS 请求实际进入中间件后才生效;而它能否进入,完全取决于你有没有提前注册好 OPTIONS 路由。


















