直接写 corsmiddleware() 易被浏览器拒绝,因 allowcredentials:true 与 access-control-allow-origin:"*" 冲突;应动态匹配 origin 或用白名单校验,并确保预检请求正确响应。

为什么直接写 CorsMiddleware() 容易被浏览器拒绝
很多开发者手写中间件时只设 Access-Control-Allow-Origin: "*",但一旦开启 AllowCredentials: true(比如前端带 Cookie 登录),浏览器会直接拒绝响应——因为规范明确禁止 * 和 credentials 同时存在。
真正安全的做法是:动态匹配 Origin,只对可信域名回写具体值。否则要么无法携带 Cookie,要么跨域失败。
- 前端发请求带
Origin: https://admin.example.com,后端必须原样返回该值,不能写死* - 若允许多个域名,需在中间件里做白名单校验,而不是无脑放行
-
OPTIONS预检请求必须返回 204 或 200,且不能漏掉Access-Control-Allow-Methods和Access-Control-Allow-Headers
gin-contrib/cors 的三种初始化方式怎么选
这个包提供 Default()、DefaultConfig() 和 New(config) 三类入口,实际使用中差异很大:
-
cors.Default():仅允许http://localhost:*和http://127.0.0.1:*,开发调试够用,上线必须换 -
cors.DefaultConfig():返回一个可修改的 config 结构体,适合需要微调但不想写全字段的场景 -
cors.New(config):完全自定义,推荐生产环境使用;尤其注意AllowOriginFunc比AllowOrigins优先级高,可用于动态鉴权
示例中常见错误是把 AllowOrigins: []string{"*"} 当成通配符,其实它等价于 AllowAllOrigins: true,仍会和 AllowCredentials 冲突。
预检请求(OPTIONS)没响应?检查这三点
前端发 PUT/DELETE 或带自定义 Header(如 Authorization)时,浏览器先发 OPTIONS 请求。如果后端没正确处理,就会卡住或报 404/500。
- 确保中间件注册在所有路由之前:
r.Use(cors.New(...))必须在r.GET等定义之前 - 确认
AllowMethods包含"OPTIONS"(cors.DefaultConfig()默认已包含) - 不要在业务 handler 里手动写
c.Header()覆盖 CORS 头,中间件已统一设置,重复写可能出错
生产环境必须关闭 AllowAllOrigins
本地开发用 AllowAllOrigins: true 很方便,但上线后等于把 API 暴露给任意网站——攻击者可伪造 Referer 或 Origin,诱导用户点击恶意链接完成越权操作。
真正可控的方式是:
- 用
AllowOriginFunc做域名白名单校验,例如只放行https://app.example.com和https://admin.example.com - 配合 Nginx 在反向代理层加一层 Origin 过滤,Gin 层只信任内网转发来的请求
- 若前后端同域(如都走
https://api.example.com),根本不需要 CORS,直接关掉中间件
跨域不是开关,而是边界控制——配置项写错一个布尔值,就可能让整个鉴权体系形同虚设。











