x-frame-options必须由服务端通过http响应头设置,用于防御点击劫持;deny禁止任何嵌套,sameorigin仅允相同域名嵌套,meta标签无效,且需避免被后续handler覆盖。

用 c.Set() 写单个响应头最直接
绝大多数场景下,c.Set("X-Frame-Options", "DENY") 就够了。它底层调用的是 c.Response().Header.Set(),会覆盖同名已有头。注意:键名不区分大小写,但建议统一用 PascalCase 风格(如 "Content-Type"),避免某些代理或 CDN 误解。
c.Append() 和 c.Set() 的行为差异必须分清
当需要追加而非覆盖时,比如往 Cache-Control 里加 no-transform,就得用 c.Append("Cache-Control", "no-transform")。否则 c.Set("Cache-Control", "no-cache") 会把之前所有值全干掉。常见踩坑点:
-
c.Set("Set-Cookie", ...)会覆盖整个 Cookie 字段,导致多个Set-Cookie头只剩一个 -
c.Append("Set-Cookie", ...)才能安全写入多条 Cookie -
c.Append()对非重复型头(如Content-Type)无效,它只对允许重复的头起作用
批量设置响应头要用 c.Response().Header 原生接口
如果要一次塞一堆头,比如 CORS 配置,别一个个 Set(),直接操作底层 Header map 更高效:
h := c.Response().Header
h.Set("Access-Control-Allow-Origin", "*")
h.Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE")
h.Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
这样避免了 Fiber 封装层的额外判断,也更贴近 net/http 原生习惯。但注意:不能在 c.Send() 或 c.JSON() 之后调用,否则 Header 已被写出,再设无效。
响应头在中间件里设置容易被后续 handler 覆盖
比如你在全局中间件里写了 c.Set("X-Request-ID", uuid.New().String()),但某个路由 handler 又调了 c.JSON(...) —— 它内部可能重设了 Content-Type,甚至某些自定义中间件会清空 Header。关键原则:
- 通用头(如
X-Request-ID、X-Env)尽量在第一个中间件里设,并确保它位于所有可能改 Header 的 handler 之前 - 业务相关头(如
Content-Disposition)必须在具体 handler 里设,且紧挨着c.SendFile()或c.SendString()调用 - 不要依赖
ctx.Locals存 Header 值再统一输出——Fiber 不提供“响应头收集器”机制,Header 必须显式写入











