在iris中,中间件修改响应头须在handler写入响应体前调用header().set();若需根据最终状态码动态设头,应使用ctx.onsuccess()钩子。

中间件里用 ctx.ResponseWriter().Header().Set() 添加响应头
在 Iris 中,中间件修改响应头必须在 ctx.Next() 之前或之后调用 Header().Set(),但要注意:如果 handler 已经写入响应体(比如调用了 ctx.JSON() 或 ctx.WriteString()),再设 Header 就无效了——HTTP 规范要求 Header 必须在 body 之前发送。
典型做法是提前设置,尤其适合跨域、缓存、安全类头:
app.Use(func(ctx iris.Context) {
ctx.ResponseWriter().Header().Set("X-Frame-Options", "DENY")
ctx.ResponseWriter().Header().Set("X-Content-Type-Options", "nosniff")
ctx.Next() // 执行后续 handler
})
需要动态值时,必须在 ctx.Next() 之后读取状态码或响应长度
比如你想根据最终响应状态码添加不同头(如 404 时加 X-Debug),就不能在 ctx.Next() 前设,因为此时状态码还是默认的 200。Iris 提供 ctx.Record() 和 ctx.IsStopped() 配合使用,但更稳妥的是用 ctx.OnSuccess() 或直接监听 ResponseWriter 的写入时机。
实际中推荐用 ctx.OnSuccess()(它在响应真正写出前触发):
app.Use(func(ctx iris.Context) {
ctx.OnSuccess(func() {
if ctx.GetStatusCode() == 404 {
ctx.Header("X-Debug", "not-found-handler-ran")
}
})
ctx.Next()
})
-
OnSuccess()是 Iris 内置钩子,比手动包装ResponseWriter更轻量 - 不要在
OnSuccess()里调用ctx.Stop()或再次写响应,否则会 panic - 若需修改响应体内容(如注入 HTML),得用
ctx.Recorder().SetBody(),但 Header 修改不受影响
注意 ctx.Header() 和 ctx.ResponseWriter().Header().Set() 的行为差异
两者都操作同一个底层 Header map,但 ctx.Header() 是封装方法,会自动处理重复键合并逻辑(如多次调用 ctx.Header("Set-Cookie", ...) 会追加而非覆盖),而 ResponseWriter().Header().Set() 是纯覆盖。
常见误用场景:
- 用
Set()设多个Set-Cookie→ 只保留最后一个 - 用
ctx.Header()设Content-Type→ 正确,它会覆盖旧值 - 想设
Cache-Control: public, max-age=3600→ 两种方式都行,但别混用避免混淆
统一建议:简单静态头用 ctx.Header();需要精确控制(如避免自动合并)或调试底层行为时,才直取 ResponseWriter().Header()。
全局中间件 vs 路由级中间件对响应头的影响
全局中间件(app.Use())设置的头会作用于所有匹配路由,包括静态文件和错误处理器;路由级中间件(app.Get("/api", middleware, handler))只影响该路由链。这点容易被忽略,导致 CORS 头漏加到 /health 这类路径上。
实操建议:
- CORS、安全类头尽量走全局中间件,避免遗漏
- 业务相关头(如
X-Request-ID)可放在路由级,便于按模块控制 - 如果用了
app.RegisterView()渲染模板,全局中间件仍生效,但注意模板渲染可能已触发 header 写出 - 静态文件服务(
app.HandleDir())也会受全局中间件影响,需确认是否真要给.js文件加X-Frame-Options
最常被绕过的点是:404 和 500 错误页面默认不经过你写的中间件链,除非你显式用 app.OnErrorCode(404, ...) 注册了自定义错误处理器并手动调用中间件逻辑。











