
本文详解 gin 中 cors 中间件的常见错误与正确写法,重点解决 options 预检请求后无响应、跨域失败等问题,提供可直接使用的健壮中间件实现及关键配置说明。
在使用 Gin 构建 Web API 时,前端(如 React/Vue)发起跨域请求常触发浏览器的 CORS 预检(Preflight)机制——即先发送一个 OPTIONS 请求,待服务端明确允许后,才执行真正的 GET/POST 等请求。若中间件处理不当,即使返回了 200 OK,也可能因响应体缺失、状态码不规范或头信息冲突导致预检失败,表现为“请求静默终止”或控制台报错 CORS header ‘Access-Control-Allow-Origin’ missing。
以下是一个生产可用、符合 W3C CORS 规范的 Gin CORS 中间件实现:
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 允许任意源(开发环境可用;生产环境建议指定明确域名,如 "https://your-app.com")
c.Header("Access-Control-Allow-Origin", "*")
// 允许携带认证信息(cookies、Authorization header等),注意:Allow-Origin 不能为 "*" 时才可设为 true
c.Header("Access-Control-Allow-Credentials", "true")
// 明确声明允许的请求头,需覆盖前端实际发送的所有自定义 Header(如 Authorization、X-Requested-With)
c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
// 声明允许的 HTTP 方法
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, PATCH")
// 关键:OPTIONS 请求必须立即终止链路,并返回 204 No Content(非 200)
// 浏览器要求预检响应不能包含 body,204 是语义最准确的状态码
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}? 重要注意事项:
- ✅ 状态码必须为 204:c.AbortWithStatus(200) 是常见错误。W3C 规范要求预检响应不得有响应体,204 No Content 是标准且安全的选择;200 可能被某些代理或浏览器拒绝。
- ✅ Access-Control-Allow-Origin 与 Access-Control-Allow-Credentials: true 不兼容通配符:若需携带 cookies 或 token,Allow-Origin 必须设为具体域名(如 "https://example.com"),不可用 "*",否则浏览器将拒绝响应。此时建议动态匹配 Origin 头:
origin := c.Request.Header.Get("Origin") if origin != "" { c.Header("Access-Control-Allow-Origin", origin) } - ✅ Access-Control-Allow-Headers 需覆盖全部自定义头:例如前端设置了 Authorization: Bearer xxx 或 X-Requested-With: XMLHttpRequest,就必须显式列出,否则预检失败。
- ✅ 注册顺序很重要:CORS 中间件应置于路由注册前,确保所有路由生效:
r := gin.Default() r.Use(CORSMiddleware()) // ✅ 在 Use 中注册 r.GET("/api/data", handler)
? 进阶建议:
对于生产环境,推荐使用成熟库 gin-contrib/cors,它支持精细配置(如白名单域名、暴露头、缓存时间等),并已通过大量场景验证:
go get github.com/gin-contrib/cors
import "github.com/gin-contrib/cors"
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
}))正确实现 CORS 不仅关乎头信息设置,更在于对 HTTP 协议语义和浏览器行为的精准理解。从 204 状态码到头字段的互斥约束,每一步都影响跨域调用的成败。










