Gin默认不处理跨域,必须手动添加中间件;若注册顺序错误、OPTIONS预检未正确响应(应返回204且立即终止)、或AllowCredentials为true时AllowOrigins含*,前端带Cookie请求必然失败。

直接说结论:Gin 默认不处理跨域,必须手动加中间件;但加错位置、写死 * 且开启 AllowCredentials: true,前端带 Cookie 的请求必然失败。
为什么 OPTIONS 预检总被拒绝?
浏览器对非简单请求(如 PUT、Content-Type: application/json、带自定义 Header)会先发 OPTIONS 请求。如果中间件没正确响应这个预检,后续请求根本不会发出。
- 中间件必须在
c.Next()之前拦截OPTIONS,并用c.AbortWithStatus(204)或200立即返回,不能继续走路由逻辑 - 不能在
c.Next()之后才设Access-Control-Allow-Origin—— 此时响应头已部分写出,再设会 panic 或被忽略 - 别用
c.JSON()响应 OPTIONS,它会自动加Content-Type: application/json,而预检要求响应体为空、状态码为204更稳妥
gin-contrib/cors 配置踩坑点
这个库封装了常见逻辑,但几个关键配置组合极易出错:
-
AllowCredentials: true时,AllowOrigins绝对不能含"*",否则浏览器直接丢弃响应 —— 必须显式列出完整域名,如[]string{"https://admin.example.com", "http://localhost:3000"} -
AllowOriginFunc优先级高于AllowOrigins,适合动态校验 Origin(比如从数据库查白名单),但函数内不能 panic,否则整个请求崩溃 -
AllowHeaders要包含前端实际发送的自定义头,比如"Authorization"、"X-Request-ID",漏一个就会导致预检失败
自己写最小可用中间件的关键逻辑
不依赖第三方时,核心就三行:判断是否 OPTIONS、设置必要响应头、放行或终止。其余都是干扰项。
- 先取
c.Request.Header.Get("Origin"),为空则跳过(说明不是跨域请求) - 若需支持凭证,必须根据 Origin 白名单动态写
Access-Control-Allow-Origin,不能硬编码"*" - 务必在
if c.Request.Method == "OPTIONS"分支里调用c.AbortWithStatus(204),不要用c.Status(204)+c.Next()—— 后者仍会执行后续中间件 -
Access-Control-Allow-Credentials和Access-Control-Allow-Origin必须成对出现,且 Origin 值不能是"*"
最常被忽略的是:跨域配置生效的前提,是中间件必须在所有路由注册前调用 r.Use(...)。放在 r.GET() 之后,等于没配。


















