中间件需在函数体内主动跳过特定路径或方法,如用ctx.Path()判断健康检查路径、ctx.Method()拦截非目标方法,并调用ctx.Next()放行;全局app.Use()对所有路由生效,须手动过滤;OPTIONS预检请求需用ctx.StopExecution()终止执行。

中间件里怎么跳过特定路径或方法
中间件默认对所有匹配请求生效,但常需排除健康检查、静态资源或预检请求。关键不是“不注册”,而是注册后在函数体内主动跳过。
- 用
ctx.Path()判断路径前缀:if strings.HasPrefix(ctx.Path(), "/health") || ctx.Path() == "/favicon.ico" { ctx.Next(); return } - 用
ctx.Method()拦截非目标方法:if ctx.Method() != "POST" && ctx.Method() != "PUT" { ctx.Next(); return } - 别只靠
ctx.Request().URL.Path—— 它没经过路由解析,可能含查询参数或未解码字符,ctx.Path()才是标准化后的路径 - 跳过时仍要调
ctx.Next(),否则后续中间件和 handler 都不会执行;但不能在跳过分支里写响应(如ctx.StatusCode(200)),否则会污染流程
为什么 app.Use() 注册的中间件还会执行到 /api/* 以外的路径
app.Use() 是全局注册,它对所有已注册路由(包括 /、/health、/favicon.ico)都生效。Iris 不做路径白名单自动过滤,必须手动控制。
- 常见误操作:只在中间件开头加日志,发现连
GET /都进了鉴权逻辑 —— 这不是 bug,是设计如此 - 正确做法是在中间件最开始就做路径/方法判断,早判早放行,避免无谓计算
- 若想彻底隔离,应改用分组注册:
api := app.Party("/api"); api.Use(authMiddleware),这样/health就天然绕过 - 注意:分组
Use()不影响父级或兄弟分组,不存在“继承”或“穿透”
如何让中间件对 OPTIONS 预检请求静默放行
CORS 预检请求(OPTIONS)通常不需要业务逻辑处理,但中间件若没识别它,可能因读取 body 或校验 token 导致 panic 或 401。
- 必须在中间件开头判断:
if ctx.Method() == "OPTIONS" { ctx.StatusCode(204); ctx.StopExecution(); return } - 不能只写
ctx.StatusCode(204)就结束 —— 缺少ctx.StopExecution()会让请求继续进下游 handler,而 handler 很可能没处理 OPTIONS,直接 panic - 更稳妥的做法是配合显式 OPTIONS 路由:
app.Options("*", func(ctx iris.Context) { ctx.StatusCode(204) }),确保预检一定被接住,中间件反而可专注业务路径 - 如果中间件依赖
ctx.ReadBody(),OPTIONS 请求必须跳过,否则ctx.Request().Body已被消耗,后续 handler 读不到原始数据
子分组中间件如何避免重复执行父级逻辑
当 app.Use(m1) 和 api.Use(m2) 同时存在,/api/user 会依次执行 m1 → m2 → handler。若 m1 是日志,m2 也是日志,就会打两遍。
- 不要指望子分组能“覆盖”父级中间件 —— Iris 中间件链是追加式,不是替换式
- 解决方式一:把公共逻辑抽成条件型中间件,在
m1里加路径判断:if !strings.HasPrefix(ctx.Path(), "/api/") { logRequest(ctx) } - 解决方式二:放弃全局
app.Use(),全部改用分组注册,按需挂载,比如public.Use(logger)、api.Use(auth, logger) - 切忌在
m2里手动调m1(ctx)—— 这会破坏执行顺序,且ctx.Next()行为不可控
真正容易被忽略的是:中间件跳过 ≠ 中间件不执行。哪怕你写了 return,只要没调 ctx.StopExecution(),Iris 仍可能在某个环节继续流转,尤其当多个中间件嵌套、且部分分支漏掉终止时,越权或重复执行的风险就藏在这里。


















