fiber.cors()默认alloworigins=["*"],与allowcredentials=true冲突导致浏览器静默拒绝;必须显式配置allowcredentials:true并禁用通配符,改用alloworiginfunc动态校验或明确列出可信源。

直接用 fiber.Cors() 中间件,但默认配置在带凭证(credentials: 'include')时会静默失败——必须显式传入 AllowCredentials: true 且禁用 AllowOrigins: []string{"*"}。
fiber.Cors() 默认不支持 credentials 场景
Fiber 的 fiber.Cors() 默认启用 AllowOrigins: []string{"*"},这在前端发请求带 credentials: 'include' 时,浏览器会直接拒绝响应,控制台甚至不报错,只显示“CORS error”。这不是 Fiber bug,是浏览器硬性限制:一旦响应头含 Access-Control-Allow-Credentials: "true",Access-Control-Allow-Origin 就不能是 "*"。
常见错误现象:
- 前端登录后调用接口始终 401,但后端日志显示请求根本没进来(其实是 OPTIONS 预检被拒)
- Postman 能通,浏览器 fetch 不行——因为 Postman 不走 CORS 检查
正确做法:
- 开发环境:显式写死白名单,例如
AllowOrigins: []string{"http://localhost:3000", "http://127.0.0.1:3000"} - 生产环境:必须用
AllowOriginFunc动态校验,不能依赖AllowOrigins - 务必配对设置:
AllowCredentials: true+AllowOriginFunc或具体域名列表
如何安全使用 AllowOriginFunc 动态白名单
AllowOriginFunc 是 Fiber CORS 中唯一能兼顾安全性与灵活性的方式,尤其适合多租户、灰度发布或前端子域频繁变更的场景。它会在每次请求(包括 OPTIONS)时执行,返回 true 才写 Access-Control-Allow-Origin 头。
容易踩的坑:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 函数里没做空
Origin判断,遇到空值或file://协议直接 panic 或返回true - 同步查数据库或 HTTP 接口没加超时,拖慢所有请求
- 没缓存白名单结果,高频请求反复解析/查询
实操建议:
- 先解析
origin := r.Header.Get("Origin"),空值或非法 scheme(如data:、file:)直接 return false - 用内存 map 缓存已加载的白名单(如从 etcd/Redis 加载),避免每次请求都 IO
- 示例片段:
app.Use(fiber.Cors(&fiber.CorsConfig{ AllowCredentials: true, AllowOriginFunc: func(origin string) bool { if origin == "" { return false } u, err := url.Parse(origin) if err != nil || (u.Scheme != "http" && u.Scheme != "https") { return false } return allowedOriginsMap[origin] != nil // allowedOriginsMap 是预热好的 map[string]struct{} }, }))
OPTIONS 预检必须由 Fiber 拦截,不能透传给下游
浏览器对非简单请求(如带 Authorization、Content-Type: application/json、PUT/DELETE)会先发 OPTIONS 请求。如果 Fiber 没拦截,而是把 OPTIONS 转发给你的 handler,而 handler 又没注册该方法,就会返回 404 或 405 —— 此时预检失败,后续请求根本不会发出。
fiber.Cors() 默认已处理 OPTIONS,但要注意:
- 中间件必须放在
app.Use()中,且要早于你自定义的路由注册(否则某些路由可能绕过) - 不要在 handler 里手动写
w.Header().Set("Access-Control-Allow-Origin", ...),和中间件冲突会导致头重复或覆盖 - OPTIONS 响应必须是
204 No Content或200 OK,且响应体为空;Fiber 默认满足,但若你写了自定义 OPTIONS handler,得手动c.SendStatus(fiber.StatusNoContent)
Vary: Origin 头必须存在,否则 CDN 或代理可能缓存错误响应
当 Access-Control-Allow-Origin 值随请求的 Origin 头动态变化时,必须返回 Vary: Origin,否则中间代理(如 Nginx、Cloudflare)可能把为 https://a.com 生成的响应缓存下来,再返回给 https://b.com,导致跨域失败。
Fiber 的 fiber.Cors() 在启用 AllowOriginFunc 或非通配符 AllowOrigins 时会自动加 Vary: Origin,但如果你手写中间件或混用其他 CORS 包,就得自己补:
-
c.Set("Vary", "Origin")必须在所有 CORS 头设置之后、响应写出之前调用 - 别漏掉 OPTIONS 请求——它也要有
Vary: Origin - 检查最终响应是否真包含该头:用
curl -I http://localhost:3000/api/xxx -H "Origin: https://example.com"
最易被忽略的是:动态 Origin + CDN 缓存 + 缺 Vary,问题只在线上偶发,复现困难,排查时容易误判为前端或网络问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










