中间件执行顺序由注册顺序决定,useglobal() 最先执行,子分组 use() 追加而非覆盖;必须显式调用 ctx.next() 并配对 ctx.stopexecution(),跨层共享数据应使用 ctx.values() 配合类型检查。

子分组调用 Use() 是追加而非覆盖
父分组注册的中间件不会被子分组 Use() 覆盖,而是按注册顺序串联执行。比如 api.Use(m1) 后再 v1 := api.Party("/v1"); v1.Use(m2),最终请求 /api/v1/xxx 的执行顺序是 m1 → m2 → handler。
常见错误是以为子分组能“重置”中间件链,结果发现日志、鉴权等逻辑重复执行或顺序错乱。
- 中间件注册顺序 = 执行顺序,和路由嵌套层级无关
- 若需跳过某层中间件(如 v1 下禁用日志),不能靠“不调用
Use()”,而要改用条件判断(如检查路径前缀)或单独定义无该中间件的分组 -
UseGlobal()注册的中间件优先级最高,最先执行,且对所有路由生效
ctx.Next() 不等于“自动继续”,必须显式控制流程
中间件里漏掉 ctx.Next() 或位置放错,会导致后续 handler 完全不执行;反过来,写在响应后还调用 ctx.Next(),可能引发 panic 或重复写响应。
典型反模式:if err != nil { ctx.StatusCode(400); ctx.JSON(err); } ctx.Next() —— 错误分支没阻断,ctx.Next() 仍会执行。
- 所有提前返回逻辑(如校验失败、权限拒绝)之后,必须跟
ctx.StopExecution() -
ctx.Next()应放在所有条件分支之后,仅当确定要继续时才调用 - 不要用
defer ctx.Next(),Iris 不支持 defer 形式的中间件流转
多级中间件中如何共享上下文状态
跨层级中间件通信不能依赖局部变量,得用 ctx.Values() 存取键值对。比如认证中间件存用户,日志中间件读取并打到字段里。
容易踩的坑是键名冲突或类型断言失败:同一 key 被不同中间件反复写入,或未做 value, ok := ctx.Values().Get("user").(*User) 类型检查就直接使用。
- 推荐用常量定义 key,如
const CtxKeyUser = "user" - 写入前建议先
ctx.Values().Delete(key)清理旧值,避免残留 - 读取时务必检查
ok,否则 panic
为什么 UseGlobal() 中间件总在最前执行
UseGlobal() 注册的中间件在路由匹配前就介入,所以它能看到原始请求,也适合做全局监控、请求 ID 注入、强制 HTTPS 重定向等前置操作。
但这也意味着它无法访问 ctx.Params()(路由参数尚未解析),也不能调用 ctx.GetCurrentRoute() 获取当前路由信息。
- 不要在
UseGlobal()中做依赖路径参数或路由元信息的逻辑 - 若需同时使用全局和分组中间件,注意
UseGlobal()的副作用可能影响下游中间件行为(如修改了请求体但未重置 body reader) - 调试时可加日志输出
ctx.HandlerName(),确认执行时机是否符合预期
ctx.Values() 的生命周期和 StopExecution() 的触发点,稍不注意就会出现静默失败或响应重复写入。











