生产环境必须用 fiber.New() 初始化并手动挂载 cors.New(),因 fiber.Default() 默认不发CORS头且中间件顺序不可调;带Credentials时AllowOrigins不能为"*",须精确匹配协议、主机、端口,并设AllowCredentials=true、ExposeHeaders;静态资源路由需跳过CORS。

生产环境必须用 fiber.New() 初始化并手动挂载 cors.New(),fiber.Default() 默认允许所有源,等同于关闭跨域防护。
为什么 fiber.Default() 不能直接配 CORS
fiber.Default() 内置了 Logger、Recover 和无采样 RequestID,但它的 cors 行为是隐式的:不注册任何中间件时,压根不发 CORS 响应头;一旦你调用 cors.New() 却没传 AllowOrigins,它会 fallback 到默认值 "*"——这在带 Credentials 的请求下直接被浏览器拒绝,且无法通过预检。
更关键的是:fiber.Default() 启动的实例已经绑定了高危中间件,你无法安全地“覆盖”或“重排”中间件顺序。CORS 必须在日志和恢复逻辑之前生效,否则错误堆栈可能泄露敏感信息。
cors.New() 的白名单必须精确匹配协议、主机、端口
常见失效场景不是代码写错,而是 URL 字符串不一致:
- 前端请求
Origin: https://a.com:8080,但白名单只写了"https://a.com"→ 拒绝 - 前端访问
https://b.com/(结尾有斜杠),白名单是"https://b.com"(无斜杠)→ 拒绝(cors库做的是字符串全等比对,不自动 normalize) - 开发时用
http://localhost:3000,但白名单漏了http://前缀 → 拒绝
建议统一用 new URL(origin).origin 提取并校验,或直接从环境变量读取完整 origin 列表,避免硬编码拼接。
带凭证(Cookie / Authorization)时的强制约束
只要前端设置了 credentials: 'include' 或后端需读取 Cookie,就必须同时满足:
-
AllowOrigins不能是"*",必须显式列出每个完整 origin -
AllowCredentials设为true -
ExposeHeaders显式声明需要前端 JS 读取的响应头(如"X-Request-ID")
漏任一条件,浏览器会静默拦截响应。例如:
app.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://admin.example.com", "https://app.example.com"},
AllowCredentials: true,
ExposeHeaders: []string{"X-Request-ID", "Content-Length"},
}))静态资源路由必须跳过 CORS 中间件
/public/*、/assets/* 这类路径通常由 Nginx 或 Fiber 静态服务直接返回,不应经过 cors.New()。否则可能因中间件顺序或 OPTIONS 路由缺失导致 404 或预检失败。
正确做法是分组隔离:
api := app.Group("/api")
api.Use(cors.New(cors.Config{ /* ... */ }))
api.Get("/users", handler)
<p>// 静态资源走独立路由,不套 CORS
app.Static("/public", "./public")注意:不要把 app.Use(cors.New(...)) 放在 app.Static() 之后——Fiber 中间件是链式执行,静态文件中间件若未命中,会继续往下走,可能意外触发 CORS 校验逻辑。
最易被忽略的一点:CORS 白名单不是“配置完就生效”,而是每次请求都做字符串比对。如果你用环境变量注入 origin 列表,确保部署时该变量已加载且未被截断或包含不可见字符(比如换行符)。线上排查时,先 fmt.Println 打印出实际传给 cors.New() 的 AllowOrigins 值,再比对浏览器 Origin 请求头,比看文档更快定位问题。


















