最稳妥的跨域方案是 gin-contrib/cors,但 AllowOrigins 配置错误或误开 AllowCredentials:true 会导致前端请求静默失败;带 cookie 时 AllowOrigins 不能为 "*",必须精确匹配 Origin;开发时多端口应使用 AllowOriginFunc,生产禁用 AllowAllOrigins:true;支持 credentials 需前后端一致配置、精确 Origin、显式 credentials:"include";调试应优先检查 OPTIONS 响应头。

直接说结论:用 gin-contrib/cors 是最稳妥的方案,但填错 AllowOrigins 或误开 AllowCredentials: true 会导致前端请求静默失败——浏览器根本不会发实际请求,连 Network 面板都看不到。
为什么 AllowOrigins: []string{"*"} 在带 cookie 时无效?
浏览器明确禁止:当响应头中包含 Access-Control-Allow-Credentials: true 时,Access-Control-Allow-Origin 的值**不能是 "*"**,必须是具体 Origin 字符串(如 "https://admin.example.com")。否则预检通过后,真实请求会被拦截,控制台只报 “CORS header ‘Access-Control-Allow-Origin’ cannot be the wildcard ‘*’”。
- 开发时若需支持多个 localhost 端口(如
http://localhost:3000、http://localhost:3001),别写死数组,改用AllowOriginFunc - 生产环境绝不能留
AllowAllOrigins: true,它和AllowCredentials: true互斥,启用即失效 - 如果后端没收到 OPTIONS 请求,大概率是前端发的不是预检触发条件(比如 Content-Type 是
application/json),但中间件没配AllowHeaders导致预检被拒
如何安全地支持带 cookie 的跨域请求?
这是最易出错的场景。关键约束有三条:Origin 必须精确匹配、Credentials 开关前后端必须一致、响应头不能漏设。
-
AllowCredentials设为true时,AllowOrigins必须是非空切片,且每个元素是完整协议+域名+端口("https://a.com"可,"a.com"不可) - 前端 fetch 必须显式加
credentials: "include",否则后端即使开了也不传 cookie - 后端响应里
Access-Control-Allow-Origin必须和请求头中的Origin完全一致——不能靠"*"替代,也不能自动补协议
什么时候该放弃 gin-contrib/cors,自己写中间件?
当你需要动态 Origin 校验(比如按用户角色放行不同域名)、或要兼容旧版 IE(不支持 Access-Control-Allow-Credentials)、或调试时想看清每一步 Header 设置逻辑,就该手写。
- 必须在
c.Request.Method == "OPTIONS"时调用c.AbortWithStatus(204),不能用c.JSON或c.String,否则响应体非空,浏览器拒绝预检通过 - 所有
c.Header()调用必须放在c.Next()之后(即业务 handler 执行完再统一设头),否则预检响应里缺头,或业务响应被重复覆盖 - 如果从
Origin头取值回写,务必白名单校验——直接 echo 原始Origin是 XSS 风险点
真正麻烦的从来不是“怎么配”,而是“为什么配了还不生效”。多数问题出在 AllowCredentials 和 AllowOrigins 的组合约束上,或者前端没发对预检触发条件。多看一眼 Network 里的 OPTIONS 响应头,比反复改 Go 代码更高效。











