go的http包本身不处理跨域,问题根源在浏览器同源策略;必须正确返回cors响应头并显式处理options预检请求,否则会因404/405、credentials与*冲突或缺失vary: origin导致静默失败。

Go 的 http 包本身不设跨域限制——所谓“跨域问题”从来不是 Go 服务端拦的,而是浏览器基于同源策略主动拒绝接收响应。想“搞定”,得让服务端正确返回 Access-Control-Allow-Origin 等响应头。
为什么加了 CORS 头还是报错?检查预检请求(OPTIONS)是否被忽略
当请求带 Authorization、自定义 header 或非简单方法(如 PATCH),浏览器会先发一个 OPTIONS 预检请求。如果 Go 服务没注册 OPTIONS 路由或中间件未处理它,就会 404 或 405,导致后续请求根本不会发出。
- 用
net/http时,必须显式处理OPTIONS:在路由中添加http.HandleFunc("OPTIONS", ...),或在中间件里对r.Method == "OPTIONS"提前返回200 - 用
gin时,gin.Default()不自动处理预检;推荐用github.com/rs/cors或手动注册router.OPTIONS("/path", handler) - 检查实际网络面板:确认预检请求状态码是
200,且响应头包含Access-Control-Allow-Methods和Access-Control-Allow-Headers
使用 github.com/rs/cors 时,AllowedOrigins 配置别写死 "*"
"*" 看似省事,但一旦设置了 Access-Control-Allow-Credentials: true(比如要带 cookie),浏览器会直接拒绝响应——这是规范强制要求。
- 需要凭据时,
AllowedOrigins必须是具体域名列表,例如[]string{"https://example.com", "http://localhost:3000"} - 开发时可动态匹配:用
func(origin string) bool回调校验 origin 是否在白名单,避免硬编码泄露生产配置 - 注意协议、端口、斜杠都要一致:
http://localhost和http://localhost:8080是不同源
用 net/http 手写中间件,别漏掉 Vary: Origin
这个响应头告诉缓存代理(如 CDN、反向代理):该响应依赖于 Origin 请求头,不能把为 A 域名生成的响应缓存后返回给 B 域名——否则可能泄露敏感 CORS 头或触发安全错误。
- 手写中间件时,在写入
Access-Control-Allow-Origin后,务必加一行:w.Header().Set("Vary", "Origin") - 如果用了 Nginx 做反向代理,也要确保它不覆盖或丢弃这个头;可用
curl -I验证最终响应是否含Vary: Origin - 漏掉它不会立刻报错,但在有缓存层的生产环境可能导致偶发跨域失败,排查成本极高
真正麻烦的从来不是加几个 header,而是预检请求的静默失败、凭据与通配符的互斥、以及缓存层对 Vary 的忽略——这三处最容易在线上突然出问题,且现象不直观。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











