不能用 responsewriter.header().set(),因为 beego 在 servejson() 等输出前会重置 header;this.ctx.output.header() 是线程安全的封装,确保 header 在最终写出时生效,且必须在任何输出动作前调用。

this.Ctx.Output.Header() 是 Beego 中设置响应头的唯一推荐方式,直接操作 http.ResponseWriter 的 Header().Set() 会因框架内部写入逻辑被覆盖而失效。
为什么不能用 ResponseWriter.Header().Set()?
Beego 在 ServeJSON()、Output.Body() 或模板渲染前会重置或覆盖原始 Header;this.Ctx.ResponseWriter 是裸响应对象,未经过 Beego 输出管道的封装,绕过它等于放弃框架对 Content-Type、状态码、编码等的自动管理。实测中,手动调用 w.Header().Set("X-Frame-Options", "DENY") 后再调用 this.ServeJSON(),该 Header 很可能不会出现在最终响应里。
Header() 必须在 Write 前调用且不可重复覆盖
this.Ctx.Output.Header() 是线程安全的封装,它把 Header 写入内部缓冲,确保在最终写出时生效。但要注意:
- 多次对同一 key 调用
Header("X-Frame-Options", "DENY")会覆盖前值,不是追加 - 必须在任何输出动作(如
ServeJSON()、Render()、Output.Body())之前调用,否则无效 - 若需设置多个值(如多个
Cache-Control指令),应拼成单个字符串:this.Ctx.Output.Header("Cache-Control", "no-cache, no-store, must-revalidate")
常见响应头设置场景与参数差异
不同用途的响应头,其取值和时机有明显区别:
-
CORS 相关:跨域时需同时设
"Access-Control-Allow-Origin"和"Access-Control-Allow-Methods";若前端带 credentials,还必须显式设"Access-Control-Allow-Credentials"为"true",且 Origin 不能为"*" -
安全头:如
"X-Content-Type-Options: nosniff"、"X-Frame-Options: DENY"应在所有接口统一设置,建议放在基类控制器的Prepare()方法中 -
缓存控制:静态资源接口可用
"Cache-Control: public, max-age=31536000",API 接口通常设为"no-store"防止敏感数据被缓存 -
下载文件:用
this.Ctx.Output.Header("Content-Disposition", "attachment; filename=\"report.pdf\""),注意 filename 值需 UTF-8 编码并按 RFC 5987 处理中文(Beego 不自动转义)
Finish() 不是设置响应头的时机
Finish() 是控制器生命周期最后一个钩子,它在 HTTP 响应已写入连接、所有中间件收尾逻辑完成之后才执行——此时连接很可能已关闭,再调用 Header() 完全无效。它适合做日志记录、资源清理,但绝不适合干预响应内容或头信息。
Header() 不校验 key 格式,传入非法名称(如含空格或控制字符)也不会报错,但会导致整个响应头解析失败,Nginx 或浏览器可能静默丢弃该响应。务必保证 key 符合 RFC 7230 规范,例如用 "X-Request-ID" 而非 "X Request ID"。











