go 的 net/http 包完全不处理 cors,必须手动或用 gorilla/handlers.cors 等中间件显式设置响应头;手写易因未处理 options、allow-origin 与 allow-credentials 冲突、header 设置过晚而失败,nginx 还需正确透传 header。

Go 的 net/http 包压根不处理 CORS,浏览器看到缺头就直接拦截,不是“配置没生效”,是根本没发过去——你得自己补,或用靠谱中间件兜底。
为什么手写 header 容易失败
常见现象:前端 fetch 报 No 'Access-Control-Allow-Origin' header,或 OPTIONS 请求返回 404/405。本质是漏了三件事:没响应 OPTIONS、Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials: true 冲突、header 写晚了(在 w.WriteHeader() 之后调用无效)。
- 只设
Access-Control-Allow-Origin不够,必须同步配Allow-Methods、Allow-Headers,否则预检失败 -
Allow-Credentials: true时,Allow-Origin不能是*,否则浏览器静默拒绝 - OPTIONS 请求必须返回
http.StatusNoContent(204)且无响应体,返回 200 或带 body 会导致某些浏览器拒收 - header 必须在任何
w.Write()或w.WriteHeader()前设置,顺序错了就白写
gorilla/handlers.CORS 是最稳的通用解法
它不依赖框架,适配原生 http.ServeMux、gorilla/mux 等,自动处理 OPTIONS、校验 origin 白名单、注入 expose headers,且参数组合清晰。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 安装:
go get github.com/gorilla/handlers - 基础用法:
http.ListenAndServe(":8080", handlers.CORS(handlers.AllowedOrigins([]string{"https://myapp.com"}))(r)) - 必须显式配全:用
handlers.AllowedMethods([]string{"GET", "POST"})、handlers.ExposedHeaders([]string{"X-Total-Count"})、handlers.MaxAge(3600) -
AllowedOrigins传["*"]会自动禁用 credentials 支持,二者不可共存
GIN 用户必须用 gin-contrib/cors
别在 handler 里调 c.Header().Set(),GIN 的 writer 封装逻辑和预检响应耦合紧密,手写极易覆盖或遗漏。
- 安装:
go get github.com/gin-contrib/cors - 注册位置:必须在
r.Use()中,且要在任何r.GET()等路由定义之前 - 生产禁用
cors.Default():它隐式关闭AllowCredentials,且MaxAge为 0 导致每次请求都触发预检 - 带凭证时,用
cors.New(cors.Config{AllowCredentials: true, AllowOrigins: []string{"https://myapp.com"}}) - 动态 origin?用
AllowOriginFunc回调,不能靠默认配置
Nginx 后面跑 Go 服务时 header 会丢
Gin 或 gorilla 返回了正确头,但浏览器仍报 CORS 错误?八成是 Nginx 拦截或覆盖了响应头。
- 禁止直接用
add_header Access-Control-Allow-Origin ...;,它会清空上游已设的 header - 正确透传:用
add_header 'Access-Control-Allow-Origin' '$sent_http_access_control_allow_origin' always; - 确保
OPTIONS请求透传给后端,不能让 Nginx 自己返回 204 —— 预检必须由 Go 服务响应 - 检查 Nginx error log,典型错误是
upstream sent no valid HTTP/1.0 header,说明 Go 服务提前写了 body
真正麻烦的不是加几个 header,而是 origin 白名单怎么管、credentials 和 * 怎么互斥、Nginx 怎么不把 header 吃掉——这些边界点一错,整个跨域链路就断在看不见的地方。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










