如何实现Golang中的跨域资源共享(CORS)?

2026-04-29 12:352阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1090个文字,预计阅读时间需要5分钟。

如何实现Golang中的跨域资源共享(CORS)?

在Go语言中,若HTTP服务默认不处理CORS,浏览器将无法直接访问。具体表现为,浏览器会显示缺少`Access-Control-Allow-Origin`标签。这通常意味着请求被直接截断,并非后端未收到请求,而是根本未发起请求。需要手动添加逻辑,并且确保OPTIONS请求得到正确处理。

怎么写一个能用的 CORS 中间件(net/http)

手写中间件最轻量,适合简单场景,但三个点不能错:

  • 所有请求(包括非 OPTIONS)都要设 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers
  • r.Method == "OPTIONS" 必须立即返回 http.StatusNoContent(204),且不能调用 next.ServeHTTP()
  • 如果前端用了 fetch({ credentials: 'include' })Access-Control-Allow-Origin 不能是 "*",得写死具体域名,比如 "https://myapp.com",同时必须加 Access-Control-Allow-Credentials: "true"

示例片段:

func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") if origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Access-Control-Allow-Credentials", "true") 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.StatusNoContent) return } next.ServeHTTP(w, r) }) }

为什么 gin-contrib/cors 比手写更稳

手写中间件容易在 AllowCredentialsAllowOrigins 配置上翻车:只要 AllowCredentials: trueAllowOrigins"*",浏览器就静默丢弃响应,Network 面板里都看不到完整失败原因。

立即学习“go语言免费学习笔记(深入)”;

  • gin-contrib/cors 自动校验二者互斥关系,AllowOrigins 设为 "*" 时会强制禁用 AllowCredentials
  • 它自动拦截并响应 OPTIONS 请求,不触发后续 handler(避免数据库误写等副作用)
  • 支持 MaxAge 缓存预检结果,减少重复 OPTIONS 往返
  • 必须在 r.Use() 中注册,且要在任何 r.GET() 等路由定义之前,否则中间件不生效

配置示例:

r.Use(cors.New(cors.Config{ AllowOrigins: []string{"https://myapp.com", "http://localhost:3000"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Content-Type", "Authorization"}, AllowCredentials: true, ExposeHeaders: []string{"X-Total-Count"}, MaxAge: 12 * 60 * 60, }))

gorilla/handlers.CORS 为什么常被选作生产方案

它比 gin-contrib/cors 更通用,适配 net/httpechofiber 等任意基于 http.Handler 的框架,且对 header 设置时机、OPTIONS 响应体、缓存控制做了更细粒度封装。

  • 若用 handlers.AllowedOrigins([]string{"*"}),它内部会自动跳过 AllowCredentials,避免浏览器报错
  • handlers.ExposedHeaders([]string{"X-Request-ID"}) 是显式白名单,没列的 header 前端 JS 拿不到
  • 注意:Nginx 后面跑 Go 服务时,必须配置 add_header Access-Control-Allow-Origin $sent_http_access_control_allow_origin always;,否则 Nginx 会清空 Go 写的 header

跨域失败时先盯住这三个地方

90% 的问题出在这三处,别一上来就改代码:

  • 浏览器 Network 面板里看 OPTIONS 请求是否返回 204/200;如果返回 404 或 405,说明路由没覆盖到 OPTIONS,中间件没注册对位置
  • 检查响应头里有没有 Access-Control-Allow-Origin,如果有但值是 "*",而前端又带了 cookie,那这个响应会被浏览器直接丢弃
  • 用 curl 模拟预检:curl -I -X OPTIONS -H "Origin: https://myapp.com" -H "Access-Control-Request-Method: POST" http://localhost:8080/api/user,看返回头是否齐全

真正难的不是加几行 header,而是理解浏览器预检机制和凭证模式之间的硬性约束——这些规则由浏览器强制执行,Go 本身无权绕过。

本文共计1090个文字,预计阅读时间需要5分钟。

如何实现Golang中的跨域资源共享(CORS)?

在Go语言中,若HTTP服务默认不处理CORS,浏览器将无法直接访问。具体表现为,浏览器会显示缺少`Access-Control-Allow-Origin`标签。这通常意味着请求被直接截断,并非后端未收到请求,而是根本未发起请求。需要手动添加逻辑,并且确保OPTIONS请求得到正确处理。

怎么写一个能用的 CORS 中间件(net/http)

手写中间件最轻量,适合简单场景,但三个点不能错:

  • 所有请求(包括非 OPTIONS)都要设 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers
  • r.Method == "OPTIONS" 必须立即返回 http.StatusNoContent(204),且不能调用 next.ServeHTTP()
  • 如果前端用了 fetch({ credentials: 'include' })Access-Control-Allow-Origin 不能是 "*",得写死具体域名,比如 "https://myapp.com",同时必须加 Access-Control-Allow-Credentials: "true"

示例片段:

func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") if origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Access-Control-Allow-Credentials", "true") 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.StatusNoContent) return } next.ServeHTTP(w, r) }) }

为什么 gin-contrib/cors 比手写更稳

手写中间件容易在 AllowCredentialsAllowOrigins 配置上翻车:只要 AllowCredentials: trueAllowOrigins"*",浏览器就静默丢弃响应,Network 面板里都看不到完整失败原因。

立即学习“go语言免费学习笔记(深入)”;

  • gin-contrib/cors 自动校验二者互斥关系,AllowOrigins 设为 "*" 时会强制禁用 AllowCredentials
  • 它自动拦截并响应 OPTIONS 请求,不触发后续 handler(避免数据库误写等副作用)
  • 支持 MaxAge 缓存预检结果,减少重复 OPTIONS 往返
  • 必须在 r.Use() 中注册,且要在任何 r.GET() 等路由定义之前,否则中间件不生效

配置示例:

r.Use(cors.New(cors.Config{ AllowOrigins: []string{"https://myapp.com", "http://localhost:3000"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Content-Type", "Authorization"}, AllowCredentials: true, ExposeHeaders: []string{"X-Total-Count"}, MaxAge: 12 * 60 * 60, }))

gorilla/handlers.CORS 为什么常被选作生产方案

它比 gin-contrib/cors 更通用,适配 net/httpechofiber 等任意基于 http.Handler 的框架,且对 header 设置时机、OPTIONS 响应体、缓存控制做了更细粒度封装。

  • 若用 handlers.AllowedOrigins([]string{"*"}),它内部会自动跳过 AllowCredentials,避免浏览器报错
  • handlers.ExposedHeaders([]string{"X-Request-ID"}) 是显式白名单,没列的 header 前端 JS 拿不到
  • 注意:Nginx 后面跑 Go 服务时,必须配置 add_header Access-Control-Allow-Origin $sent_http_access_control_allow_origin always;,否则 Nginx 会清空 Go 写的 header

跨域失败时先盯住这三个地方

90% 的问题出在这三处,别一上来就改代码:

  • 浏览器 Network 面板里看 OPTIONS 请求是否返回 204/200;如果返回 404 或 405,说明路由没覆盖到 OPTIONS,中间件没注册对位置
  • 检查响应头里有没有 Access-Control-Allow-Origin,如果有但值是 "*",而前端又带了 cookie,那这个响应会被浏览器直接丢弃
  • 用 curl 模拟预检:curl -I -X OPTIONS -H "Origin: https://myapp.com" -H "Access-Control-Request-Method: POST" http://localhost:8080/api/user,看返回头是否齐全

真正难的不是加几行 header,而是理解浏览器预检机制和凭证模式之间的硬性约束——这些规则由浏览器强制执行,Go 本身无权绕过。