全局跨域必须在路由注册前调用r.use(),否则中间件不生效;正确顺序是r := gin.default()→r.use(cors())→r.get()→r.run(),且allowcredentials为true时alloworigins绝不能含"*"。

全局跨域必须在路由注册前调用 r.Use()
中间件没生效,八成是注册顺序错了。Gin 的中间件链在请求进入时按 r.Use() 的调用顺序执行,如果写在 r.GET() 或 r.POST() 之后,那几个路由根本不会经过 CORS 中间件。正确姿势是:初始化 r := gin.New() 或 gin.Default() 后,立刻调用 r.Use(Cors()) 或 r.Use(cors.New(config)),再注册任何路由。
常见错误包括:
- 把
r.Use()放在r.LoadHTMLGlob()或r.Static()之后 - 用
gin.Default()后又漏掉手动加 CORS,误以为日志和 recovery 已经“覆盖全部” - 在子 Group(如
r.Group("/api"))里重复加中间件,但顶层没加,导致非 /api 路由(比如/health)裸奔
gin-contrib/cors 配置中 AllowOrigins 和 AllowCredentials 不能共存于 "*"
这是最常被忽略的硬性限制:只要 AllowCredentials: true,AllowOrigins 就绝不能含 "*",否则浏览器直接丢弃响应,前端控制台只显示“CORS header ‘Access-Control-Allow-Origin’ cannot match ‘*’ when credentials flag is true”。
实操建议:
- 开发环境允许多个 localhost 端口?别写
[]string{"http://localhost:*"}——gin-contrib/cors不支持通配符匹配,得用AllowOriginFunc动态判断 - 生产环境必须显式列出完整协议+域名,例如
[]string{"https://admin.example.com", "https://app.example.net"} - 若后端完全不依赖 Cookie 或 Authorization header,可关掉
AllowCredentials,此时AllowOrigins: []string{"*"}才合法
单个路由启用跨域要用 group.Use(),不是 route.Use()
Gin 不支持给单个 r.GET() 单独挂中间件。所谓“单个路由跨域”,本质是划出一个子路由组,只对这个组启用 CORS,其他路由保持默认策略。例如管理后台接口需带凭证,而公开健康检查接口不需要:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
api := r.Group("/api")
api.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://admin.example.com"},
AllowCredentials: true,
AllowHeaders: []string{"Content-Type", "Authorization"},
}))
api.GET("/users", handlerUsers)
public := r.Group("/public")
public.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowCredentials: false,
}))
public.GET("/health", handlerHealth)
注意:public.Use(...) 是对整个 /public 组生效,不是某个 GET;也别试图写 r.GET("/x").Use(...) —— 这行不通,编译会报错。
OPTIONS 预检失败时先确认是否命中了 AllowMethods 列表
前端发 POST 403、发 PUT 直接 404?大概率是 AllowMethods 没包含对应方法。浏览器对非简单请求(如 PUT、DELETE、Content-Type: application/json)强制发起 OPTIONS 预检,如果中间件配置的 AllowMethods 不含该方法,预检就失败,后续请求根本不会发出。
关键点:
-
AllowMethods必须显式包含"OPTIONS",否则预检请求被路由层 404(Gin 默认不自动注册 OPTIONS 路由) - 不要依赖
cors.Default()的默认值,它虽含 OPTIONS,但AllowOrigins: ["*"]和AllowCredentials: false是强耦合的,一改就崩 - 调试时用
curl -X OPTIONS -H "Origin: https://a.com" -I http://localhost:8080/api/foo直接看响应头,比刷前端页面快得多
真正麻烦的从来不是加几行配置,而是当 AllowCredentials: true 和动态 Origin 校验同时存在时,你得确保每次 c.Request.Header.Get("Origin") 取到的值都落在白名单里——少一个协议、多一个斜杠、端口没写全,都会让响应头失效。










