如何使用Golang解决跨域问题_Web跨域配置方法

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-MethodsAllow-Headers,导致预检(OPTIONS)失败。

处理 OPTIONS 预检请求

浏览器对非简单请求(如带 Content-Type: application/json 或自定义头)会先发一个 OPTIONS 请求。Go 默认不处理该方法,若没显式响应,会返回 405 Method Not Allowed。

你需要在路由中显式拦截 OPTIONS 并返回 200 + CORS 头,无需业务逻辑:

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 控制,别混用。