Beego处理CORS需同时满足预检与业务请求头要求;推荐用官方cors插件全局配置,注意AllowCredentials为true时AllowOrigins不可用通配符;预检失败时可手动注入Header或单独注册OPTIONS路由。

Beego框架处理跨域CORS请求时,必须同时满足浏览器预检(preflight)机制和实际业务请求的响应头要求,否则前端会卡在OPTIONS请求失败或返回数据时被拦截。
使用官方cors插件配置全局跨域
安装插件:go get github.com/beego/beego/v2/plugins/cors
在main.go或router.go的init函数中插入过滤器,注意【AllowCredentials为true时,AllowOrigins不能用通配符*,必须明确列出可信域名】。
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
AllowOrigins: []string{"http://localhost:8080", "https://admin.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Requested-With", "Accept"},
ExposeHeaders: []string{"Content-Length", "X-Total-Count"},
AllowCredentials: true,
}))
这一步必须放在所有路由注册之前,否则中间件不生效。
手动注入Header应对预检失败
当插件方式仍触发OPTIONS 405或空响应时,需在router.go中显式注册OPTIONS路由并绑定处理器。
方法一:在init函数内添加自定义filter
var corsFilter = func(ctx *context.Context) {
ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", ctx.Request.Header.Get("Origin"))
ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Origin,Content-Type,Authorization,X-Requested-With,Accept")
ctx.ResponseWriter.Header().Set("Access-Control-Allow-Credentials", "true")
ctx.ResponseWriter.Header().Set("Access-Control-Max-Age", "1728000")
if ctx.Request.Method == "OPTIONS" {
ctx.ResponseWriter.WriteHeader(200)
return
}
}
beego.InsertFilter("*", beego.BeforeRouter, corsFilter)
方法二:单独注册OPTIONS路由(推荐用于调试)
ns := beego.NewNamespace("/api",
beego.NSRouter("/users", &controllers.UserController{}, "options:Options"),
beego.NSRouter("/posts", &controllers.PostController{}, "options:Options"),
)
beego.AddNamespace(ns)
然后在对应controller中实现Options方法,直接c.ServeJSON()即可,无需返回业务数据。
控制器内按需设置响应头
第一步:在需要跨域的Action方法开头插入
c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", c.Ctx.Request.Header.Get("Origin"))
第二步:判断是否为OPTIONS请求并提前退出
if c.Ctx.Request.Method == "OPTIONS" {
c.Ctx.ResponseWriter.WriteHeader(200)
return
}
第三步:确保后续ServeJSON或Tpl输出前未覆盖Header——【ServeJSON会自动设置Content-Type,但不会覆盖已写入的Access-Control-Allow-*头】。


















