Go HTTP服务需手动设置CORS头:Access-Control-Allow-Origin、Allow-Methods、Allow-Headers,并显式处理OPTIONS预检请求;使用rs/cors库时需禁用默认配置,避免凭据与通配符冲突;Nginx共存时应由单一层统一控制CORS头。

Go HTTP 服务直接设置 CORS 头
Go 标准库 net/http 不自带 CORS 中间件,但你完全可以通过手动写入响应头解决大多数跨域场景。关键不是“加中间件”,而是确保在处理请求时正确设置了以下三个头:
-
Access-Control-Allow-Origin:必须明确指定允许的源(如"https://example.com"),或仅在调试时用"*"(注意:带凭据时不能为*) -
Access-Control-Allow-Methods:列出实际支持的动词,如"GET, POST, PUT, DELETE" -
Access-Control-Allow-Headers:前端实际发送的自定义头(如"Authorization, X-Requested-With")必须出现在这里
常见错误是只设了 Allow-Origin 却漏掉 Allow-Methods 或 Allow-Headers,导致预检(OPTIONS)失败。
处理 OPTIONS 预检请求
浏览器对非简单请求(如带 Content-Type: application/json 或自定义头)会先发一个 OPTIONS 请求。Go 默认不处理该方法,若没显式响应,会返回 405 Method Not Allowed。
你需要在路由中显式拦截 OPTIONS 并返回 200 + CORS 头,无需业务逻辑:
立即学习“go语言免费学习笔记(深入)”;
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "https://your-frontend.com")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
w.Header().Set("Access-Control-Expose-Headers", "X-Total-Count")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
注意:OPTIONS 响应里不要调用 next.ServeHTTP,否则可能触发后续 handler 的副作用(比如数据库操作)。
使用第三方库 rs/cors 的取舍
github.com/rs/cors 是最常用的 Go CORS 库,封装了预检、头设置、凭据支持等逻辑。但它不是银弹:
- 默认启用
AllowCredentials: true时,AllowOrigin必须是具体域名,不能是"*",否则浏览器拒绝(这是规范强制) - 若你用了
cors.Default(),它会自动放行所有 origin,上线前务必改掉 - 它不自动处理
Access-Control-Expose-Headers,需要手动传参配置(比如分页总数头)
推荐初始化方式:
c := cors.New(cors.Options{
AllowedOrigins: []string{"https://your-frontend.com"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Content-Type", "Authorization"},
ExposedHeaders: []string{"X-Total-Count"},
AllowCredentials: true,
})
handler := c.Handler(yourMux)
与反向代理(如 Nginx)共存时的头冲突
如果你的 Go 服务前面还有一层 Nginx,容易出现 CORS 头重复或覆盖问题。典型表现是:本地直连 Go 服务正常,部署后跨域失败。
- Nginx 可能已写了
add_header Access-Control-Allow-Origin ...,而 Go 又写一遍 → 浏览器收到多个同名头,行为未定义 - Nginx 默认不透传
OPTIONS到后端,需显式配置:if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin '*'; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization'; add_header Access-Control-Max-Age 1728000; add_header Content-Length 0; add_header Content-Type 'text/plain; charset=utf-8'; return 204; }
最稳妥的做法是:只让一层负责 CORS —— 要么全由 Go 控制,要么全由 Nginx 控制,别混用。










