Go 的 net/http 不处理 CORS,必须手动设置 Access-Control-Allow-Origin 为具体 Origin 值(不可用 "*")且需校验白名单;OPTIONS 预检须显式处理并返回 204 状态及完整 CORS 头;header 设置须在 WriteHeader 前,Nginx 需透传 Origin。

Go 的 net/http 包压根不处理 CORS,Access-Control-Allow-Origin 必须手动设,且不能只写 "*" —— 尤其当前端带 credentials: 'include' 时,必须动态校验并回写具体 Origin 值。
为什么 Access-Control-Allow-Origin: "*" 有时会报错
浏览器明确禁止 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials: "true" 同时存在且 Origin 为通配符。常见错误现象是:前端 fetch 拿到响应但控制台持续报错 “The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'”。
- 只要前端发请求时带了 cookie、
Authorization头,或显式写了{ credentials: 'include' },后端就不能用"*" - 必须读取请求头
Origin,白名单校验后原样回写:w.Header().Set("Access-Control-Allow-Origin", origin) - 白名单不能用
"https://*.example.com"—— 浏览器不认子域名通配符,只能列全[]string{"https://a.example.com", "https://b.example.com"} - 若用
gorilla/handlers.CORS,handlers.AllowedOrigins([]string{"*"})会自动禁用AllowCredentials,二者不可共存
如何正确处理 OPTIONS 预检请求
Go 默认的 http.ServeMux 对 OPTIONS 方法无路由逻辑,不匹配就直接返回 405 或 404 —— 不是你没写 handler,是请求根本没进你的业务逻辑。
- 中间件中必须显式判断
r.Method == "OPTIONS",然后立即w.WriteHeader(http.StatusNoContent)并return - 不能在
OPTIONS响应里写响应体(哪怕空字符串),否则某些浏览器拒绝后续请求 - 预检响应也必须带上所有 CORS 头:
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等,否则浏览器认为“预检失败” - 如果前端发了自定义头如
X-Auth-Token,Access-Control-Allow-Headers必须显式包含它,否则预检 403
手写中间件 vs 使用 gorilla/handlers.CORS
手写轻量中间件适合开发调试或固定源场景;gorilla/handlers.CORS 更稳,尤其涉及凭证、动态 header、缓存等复杂需求。
立即学习“go语言免费学习笔记(深入)”;
- 手写示例关键点:
origin := r.Header.Get("Origin")→ 白名单检查 →w.Header().Set("Access-Control-Allow-Origin", origin)→if r.Method == "OPTIONS" { w.WriteHeader(204); return } -
gorilla/handlers.CORS必须最外层包装最终 handler(如handlers.CORS(...)(r)),不能只包某个子路由 - 用
gorilla/handlers时,handlers.ExposedHeaders([]string{"X-Total-Count"})是必须的——否则前端response.headers.get("X-Total-Count")返回null - 注意
MaxAge单位是秒,设太大可能让前端误用过期预检缓存,调试时可先设handlers.MaxAge(10)
最容易被忽略的是 header 设置时机:所有 w.Header().Set() 必须在 w.WriteHeader() 或首次 w.Write() 之前调用,否则静默失效。另外,Nginx 反向代理时若没透传 Origin 头,后端就读不到,导致白名单校验永远失败。


















