revel 默认不内置 cors 中间件,因其遵循“显式优于隐式”设计哲学,需开发者手动配置响应头或使用 interceptor;推荐在 init() 中注册全局 interceptor,在 before_controller 阶段动态设置 cors 头并短路 options 请求。

Revel 框架本身不内置 CORS 中间件,必须手动配置 HTTP 响应头或借助第三方库,否则前端发起跨域请求会直接被浏览器拦截。
为什么 Revel 默认不处理 CORS
Revel 的设计哲学偏向“显式优于隐式”,不像 Gin 或 Echo 那样提供开箱即用的 corsMiddleware。它把跨域控制权完全交给开发者——既避免默认放行带来的安全风险,也防止误配导致生产环境暴露敏感接口。
常见错误现象包括:
- 前端 fetch 报错:
Access to fetch at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy - 预检请求(OPTIONS)返回 404 或 200 但无 CORS 头,后续实际请求仍被拒
- 带
Credentials(如 cookie)的请求失败,却忽略了Access-Control-Allow-Credentials: true和Access-Control-Allow-Origin不能为*的硬性限制
在 Revel 中添加 CORS 头的两种可靠方式
推荐优先使用 Revel 的 Interceptor 机制,在请求生命周期早期统一注入响应头,比在每个 controller 方法里重复写更可控。
实操建议:
- 在
app/init.go的init()函数中注册全局 interceptor: - 用
revel.BEFORE阶段拦截所有请求(含 OPTIONS),设置必要 header: - 对
OPTIONS请求,直接c.Result = revel.EmptyResult{}并 return,避免进入 controller
示例代码片段(放在 app/init.go 的 init() 内):
revel.Interceptors.Insert(corsInterceptor, revel.BEFORE, revel.BEFORE_CONTROLLER)
对应 corsInterceptor 实现:
func corsInterceptor(c *revel.Controller) revel.Result {
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Response.Out.Header().Set("Access-Control-Allow-Origin", origin)
c.Response.Out.Header().Set("Access-Control-Allow-Credentials", "true")
c.Response.Out.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Response.Out.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
c.Response.Out.Header().Set("Access-Control-Max-Age", "86400")
}
if c.Request.Method == "OPTIONS" {
return revel.EmptyResult{}
}
return nil
}
带 Credentials 时必须避开的坑
一旦前端 fetch 设置了 {credentials: 'include'},服务端就不能再用通配符 * 作为 Access-Control-Allow-Origin 的值,否则浏览器会直接拒绝响应。
所以:
- 不要写
c.Response.Out.Header().Set("Access-Control-Allow-Origin", "*") - 必须从
c.Request.Header.Get("Origin")动态读取并回写(如上例),且需校验该 origin 是否在白名单内(生产环境必备) - 若未校验 origin 直接回写,等于开放任意站点携带凭证访问你的 API,等同于关闭安全边界
-
Access-Control-Allow-Credentials: true和Access-Control-Allow-Origin: *同时存在,浏览器会静默忽略整个 CORS 响应
要不要用第三方 revel-cors 库
社区有 github.com/lestrrat-go/revel-cors 这类封装,但它最后更新是 2019 年,与当前 Revel v0.27+ 的 interceptor 接口不兼容,强行引入会导致编译失败或 panic。
因此:
- 不建议引入过时的第三方 CORS 包
- 手写一个不到 20 行的 interceptor 更轻量、可审计、易适配升级
- 如需复杂策略(如 per-route 白名单、动态 header 注入),可基于上述结构扩展,无需额外依赖
真正容易被忽略的是:OPTIONS 预检请求是否被路由系统正确捕获——Revel 默认不会为未定义的 OPTIONS 路由 fallback 到 interceptor,所以必须确保 interceptor 在 BEFORE_CONTROLLER 阶段生效,且不依赖任何 route 匹配逻辑。











