Go语言CORS问题本质是未提供合规OPTIONS响应:必须显式处理OPTIONS请求,且Access-Control-Allow-Origin、Methods、Headers三头缺一不可、须在WriteHeader前设置,禁止Origin为*时启用Credentials。

为什么直接写 net/http 的 Header.Set 不够用
因为跨域响应头(如 Access-Control-Allow-Origin)必须和请求匹配:预检请求(OPTIONS)要返回完整策略,简单请求只需基础头;若对所有请求一视同仁地加头,可能触发浏览器拒绝(比如 Credentials: true 时 Origin 不能为 *),或让预检失败后端不响应。
如何用中间件统一注入 CORS 头并区分请求类型
核心是判断 r.Method == "OPTIONS",再结合请求头中的 Origin 和 Access-Control-Request-Method 做动态响应。中间件需在 http.Handler 链中尽早执行,且对 OPTIONS 请求提前 return,避免后续 handler 再处理。
- 检查
r.Header.Get("Origin")是否在白名单内(不要硬编码"*") - 若为预检请求,设置
Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Max-Age,然后w.WriteHeader(http.StatusOK)并return - 非预检请求只写
Access-Control-Allow-Origin和Access-Control-Allow-Credentials(如果需要) - 注意:预检响应体应为空,且不能调用
http.Error或后续w.Write
gorilla/handlers.CORS 能直接用吗?要注意什么
能,但默认配置有陷阱。它把 AllowedOrigins 设为 ["*"] 时,会忽略 AllowCredentials,导致带 cookie 的请求被浏览器拦截。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 显式传入白名单数组,例如
handlers.AllowedOrigins([]string{"https://example.com"}) - 若需支持凭证,必须同时设
handlers.AllowCredentials(),且AllowedOrigins不能含"*" - 它自动处理
OPTIONS,但不会透传你自定义的 header(如X-Request-ID),需额外用handlers.ExposedHeaders - 性能上无明显开销,但调试时容易误以为“开了 CORS 就万事大吉”,实际仍要核对浏览器 Network 面板里的请求/响应头是否匹配
怎么验证 CORS 配置是否生效
别只靠前端页面成功就认为 OK。真实问题常出现在预检阶段,而浏览器控制台只报模糊错误(如 “CORS header ‘Access-Control-Allow-Origin’ missing”),其实可能是 Allow-Headers 没包含前端发的自定义头,或 Max-Age 过短导致频繁预检。
- 用
curl -H "Origin: https://test.com" -H "Access-Control-Request-Method: POST" -X OPTIONS http://localhost:8080/api手动触发预检,看响应头 - 检查响应中是否有
Access-Control-Allow-Origin: https://test.com,且值与请求 Origin 完全一致 - 若前端发了
X-Trace-ID,确保预检响应含Access-Control-Allow-Headers: X-Trace-ID - Chrome DevTools 的 Network → Options 请求 → Headers 标签页,比 Console 更准
最常被忽略的是:后端改了 CORS 配置,但前端没清缓存,或者反向代理(如 Nginx)覆盖了响应头 —— 这时候查 Go 代码毫无意义。

















