Beego跨域问题核心在于预检请求未响应、凭据传递失败及Allow-Origin与AllowCredentials冲突;需手动注册BeforeRouter过滤器、显式处理OPTIONS、指定具体源而非*、配置Session路径并验证响应头。

Beego 的跨域问题不是加个中间件就能一劳永逸的,核心矛盾在预检请求(OPTIONS)没被正确响应、凭据(cookie/session)传递失败、以及 Allow-Origin 与 AllowCredentials 冲突这三点。
为什么 cors.Allow 配了还报 403 或预检失败?
根本原因是 Beego 的 cors 插件默认不处理 OPTIONS 请求体——它只设响应头,不拦截并提前返回。浏览器发预检时,若后端没显式响应 200,或响应头缺失关键字段,就会直接拒绝后续请求。
- 必须确保
AllowMethods明确列出"OPTIONS",不能只写"*"(某些旧版插件不识别) -
AllowHeaders必须包含前端实际发送的字段,比如"Content-Type"、"Authorization"、"Auth-Token",漏一个就触发预检失败 - 如果启用了
AllowCredentials: true,AllowOrigins就不能用"*",必须写死域名,如"http://localhost:9090"或带通配符的"http://10.*.*.*:*" - Beego 的
cors插件不会自动拦截 OPTIONS 请求并短路响应,得靠你手动注册 Filter 时机 + 正确调用c.Abort()或返回状态码
如何让带 cookie 的登录态跨域生效?
前端 axios 设置 withCredentials: true 后,后端必须同步满足三个条件,缺一不可:
-
AllowCredentials设为true -
AllowOrigins指定具体源,不能是"*" - Beego 的 Session 必须启用且路径匹配:在
app.conf中确认sessionon = true,并设置sessionname = "beegosessionID"和sessionproviderconfig = "./tmp";同时 Cookie 路径要覆盖前端访问路径,比如前端跑在http://localhost:9090,则建议加sessioncookiepath = "/"
否则即使 CORS 头全对,浏览器也不会把 cookie 发出去,this.Ctx.Input.Session.Get("uid") 拿不到值。
Beego InsertFilter 注册位置和顺序很关键
Filter 不是“写了就生效”,必须在 web.Run() 之前注册,且执行时机选错会导致 CORS 头被覆盖或根本没机会写入。
- 务必用
web.BeforeRouter,这是最早可操作的时机,能确保所有请求(包括预检)都被捕获 - 不要用
web.AfterExec—— 此时控制器已执行完,响应头可能已被框架内部逻辑覆盖 - 注册语句必须放在
main()函数开头,或init()中;写在web.Run()后面等于没写 - 路径匹配写
"*"即可,不需要"/*"或正则,Beego 对*的匹配逻辑是“全部”
典型有效注册方式:
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
AllowOrigins: []string{"http://localhost:9090", "https://yourprod.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "Auth-Token"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
}))
开发环境快速验证但别上线的配置
仅限本地调试,避免反复改配置:
- 允许任意源 + 所有方法 + 所有头:
AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{"*"}——但注意:Go 1.20+ 的cors插件已不支持AllowHeaders: []string{"*"},会 panic,必须列明 - 若只想快速过掉预检,可自己写个极简 Filter 替代插件:
beego.InsertFilter("*", beego.BeforeRouter, func(c *context.Context) {
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Response.Header().Set("Access-Control-Allow-Origin", origin)
c.Response.Header().Set("Access-Control-Allow-Credentials", "true")
c.Response.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Response.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Authorization")
c.Response.Header().Set("Access-Control-Expose-Headers", "Content-Length")
}
if c.Request.Method == "OPTIONS" {
c.Abort(200)
return
}
})
这种写法绕过了插件限制,也更容易排查 header 是否真被写出。
最常被忽略的是:CORS 是浏览器单方面执行的策略,curl 或 Postman 测试永远成功;真正出问题一定发生在前端页面里,且错误信息藏在浏览器 DevTools 的 Network → Preview/Response Headers 里——务必看实际返回的 header,而不是只信代码里写了什么。


















