CORS 配置与跨域细节
面试问法:前后端分离项目里,GoFrame 的 CORS 怎么配?有哪些细节坑? 一句话结论:用
ghttp.CORSOptions+ 路由分组中间件即可:开发期CORSDefault()全放行;生产用AllowDomain白名单并在放行前用CORSAllowedOrigin校验 Origin;携带 Cookie 的请求不能用“通配*+ AllowCredentials”组合,来源必须精确。
要点速览
| 关注点 | 结论 |
|---|---|
| 触发条件 | 浏览器跨域请求由服务端响应头控制 |
| 配置载体 | CORSOptions + r.Response.CORS/CORSDefault/DefaultCORSOptions/CORSAllowedOrigin |
| 预检 OPTIONS | Server 按规范自动响应,前提是请求命中带 CORS 头的路由 |
| 携带 Cookie | 需 AllowCredentials + 精确来源,前端还要 withCredentials |
| 生产收敛 | 白名单域名 + 先校验后放行,非法来源直接拒绝,业务不执行 |
最短示例
// 开发环境:全放行
s.Group("/api", func(group *ghttp.RouterGroup) {
group.Middleware(func(r *ghttp.Request) {
r.Response.CORSDefault()
r.Middleware.Next()
})
group.Bind(new(v1.Controller))
})
// 生产:白名单 + 先校验再放行
group.Middleware(func(r *ghttp.Request) {
opts := r.Response.DefaultCORSOptions()
opts.AllowDomain = []string{"example.com", "admin.example.com"}
if !r.Response.CORSAllowedOrigin(opts) { // Origin 不在白名单
r.Response.WriteStatus(http.StatusForbidden)
return
}
r.Response.CORS(opts)
r.Middleware.Next()
})
细节与坑
- 凭证与通配符冲突:
Allow-Origin: *时浏览器禁止携带凭证;白名单场景须把当前 Origin 回显到 Allow-Origin。 - 中间件顺序:CORS 放最外层且在鉴权之前——否则 OPTIONS 预检被鉴权拦掉,前端表现成“跨域报错”。
- 请求带
Authorization时,AllowHeaders要包含它,否则预检失败。 - 规范路由(
group.Bind)同样适用:中间件挂分组即可,与 OpenAPI 文档可并存。 - 不要对全站一刀切放开
*,只给需要跨域的 API 分组挂 CORS。
常见追问
- 追问:本地开发为什么也跨域?——前后端端口不同即跨域;联调常用 dev 代理同源转发或临时全放行。
- 追问:预检请求每次都发吗?——浏览器按
Access-Control-Max-Age缓存预检结果,命中缓存就不再发 OPTIONS。
记忆点
- 公式:中间件 + 分组 + CORSOptions;开发 CORSDefault,生产 AllowDomain + CORSAllowedOrigin 预校验。
- Cookie 场景记住“凭证不能配通配 *”;字段细节以官方文档为准。