Go服务默认不处理CORS,必须显式配置响应头或使用rs/cors等中间件;需正确处理OPTIONS预检、凭证请求及Vary: Origin头,避免白名单、通配符与AllowCredentials三者误配。

直接结论:Go 服务默认不处理 CORS,必须显式配置响应头或用中间件
浏览器拦截跨域请求不是前端写错了,而是你的 Go 服务没告诉它“允许谁来访问”。net/http 不会自动加 Access-Control-Allow-Origin 这类头——这不是缺陷,是设计使然。你漏设、设错、或只在业务 handler 里设而没管 OPTIONS 预检,都会导致请求卡在预检阶段,控制台报 No 'Access-Control-Allow-Origin' header。
手动加头最简方案:但必须处理 OPTIONS 预检
适合调试或单路由轻量服务,但容易遗漏关键细节:
- 所有 CORS 头(
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers)必须在if r.Method == "OPTIONS"分支前就设置,否则预检响应里没有这些头,浏览器直接拒绝后续请求 - 若前端带
credentials: true(如发 Cookie),Access-Control-Allow-Origin不能为"*",必须精确匹配r.Header.Get("Origin"),且需额外加Access-Control-Allow-Credentials: "true" - 示例中常漏掉
Vary: Origin,这会导致 CDN 或代理缓存错误的响应(比如把Allow-Origin: https://a.com缓存后返回给https://b.com)
推荐用 rs/cors:生产环境最稳的选择
github.com/rs/cors 是当前最活跃、适配最全的 Go CORS 库,支持 net/http、Gin、Echo 等,对预检、凭证、动态 Origin 白名单都做了完整处理:
- 它自动识别并响应
OPTIONS请求,无需你在路由里单独判断 -
AllowedOrigins支持函数回调,可做子域匹配(如strings.HasSuffix(origin, ".example.com")),比硬编码列表更灵活 - 开启
AllowCredentials: true时,它会自动拒绝Origin: "*"的配置,防止你误配导致安全失效 - 默认添加
Vary: Origin,避免代理层缓存污染
示例:
handler := cors.New(cors.Options{
AllowedOrigins: []string{"https://app.example.com"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Content-Type", "Authorization"},
AllowCredentials: true,
}).Handler(mux)
立即学习“go语言免费学习笔记(深入)”;
别踩坑:白名单、通配符和凭证三者互斥
这是线上最常出问题的组合:
- 想用
"*"又要传 Cookie?浏览器直接报错,Allow-Credentials: true和Allow-Origin: "*"不能共存 - 用
AllowedOrigins: []string{"*"}(注意:这是 rs/cors 的特殊写法,等价于通配)+AllowCredentials: true?库会 panic 或静默禁用凭证,行为取决于版本 - 前端发的是
https://admin.example.com,但后端白名单只写了https://example.com?不匹配,CORS 失败
真正安全的做法是:开发期用明确域名(如 http://localhost:3000),上线后从配置中心加载白名单,用循环或正则校验 Origin,再动态设头——而不是靠通配符偷懒。










