cors.default()生产环境不可用,因其alloworigins设为"*"却强制allowcredentials=false,导致credentials:'include'时浏览器因安全策略屏蔽响应;应改用cors.new()显式配置可信源与凭据支持。

直接用 cors.New() 配置,别用 cors.Default() —— 它允许 * 源但禁用 AllowCredentials,前端带 cookie 就 401 或 500。
为什么 cors.Default() 在生产环境基本不能用
它等价于硬编码的宽松策略:AllowOrigins: []string{"*"},但同时强制 AllowCredentials: false。只要前端设置了 credentials: 'include'(比如要传 cookie 或 auth header),浏览器就会拒绝响应,控制台报 No 'Access-Control-Allow-Origin' header is present —— 注意,这错误不是没加 header,而是因为 * 和 AllowCredentials: true 冲突,浏览器主动屏蔽。
- 简单验证:前端 fetch 加
{ credentials: 'include' },后端用cors.Default(),必挂 - 真正需要的是明确列出可信源 + 显式开启凭据支持
-
AllowOriginFunc比AllowOrigins更安全,适合多环境(如本地开发、测试、预发)动态判断
AllowOrigins 和 AllowOriginFunc 到底怎么选
两者互斥:AllowOriginFunc 优先级更高,设了它,AllowOrigins 就被忽略。开发阶段可先用 AllowOrigins 快速验证;上线前必须切到 AllowOriginFunc 做白名单校验。
- 开发时写死:
AllowOrigins: []string{"http://localhost:3000", "https://dev.example.com"} - 上线时用函数:
AllowOriginFunc: func(origin string) bool { return strings.HasSuffix(origin, ".example.com") || origin == "https://app.example.com" } - 注意:origin 字符串可能为空(比如 curl 直连),函数里要判空,否则 panic
- 别用
strings.Contains(origin, "example.com")—— 容易被https://evil-example.com绕过
OPTIONS 预检请求失败的三个常见原因
前端发 PUT/DELETE 或带自定义 header(如 Authorization、X-Trace-ID)时,浏览器会先发 OPTIONS。如果这步卡住,实际请求根本不会发出。
-
AllowMethods漏了OPTIONS:必须显式包含,哪怕你没注册router.OPTIONS()路由 -
AllowHeaders没覆盖前端实际发的 header:比如前端加了Content-Type: application/json,但配置里只写了"Origin",预检就失败 - 中间件顺序错:
router.Use(cors.New(...))必须在router.GET()等路由注册之前,否则 OPTIONS 请求进不到 CORS 中间件
AllowCredentials 开启后必须配套处理的两件事
设 AllowCredentials: true 不是加个 flag 就完事。它要求整个链路都配合:
-
Access-Control-Allow-Origin值不能再是*,必须是具体 origin(由AllowOrigins或AllowOriginFunc返回) - 前端 fetch 必须显式声明
{ credentials: 'include' },否则 cookie 不会自动带上 - 后端 Gin 的
SetSameSite和Securecookie 属性要对齐:本地开发用SameSite=Strict+Secure=false;线上必须Secure=true且协议为 https
漏掉任一环,cookie 就失效,登录态维持不住 —— 这类问题往往查半天才发现是 AllowCredentials 和 AllowOrigins 搭配错了。











