Buffalo 不支持 CORS 插件,须手动在每个 handler 开头设置响应头;OPTIONS 预检路由需显式注册并仅设 header;Access-Control-Allow-Origin 不支持通配符与 credentials 共存,须动态白名单匹配 origin。

Buffalo 没有 CORS 插件,必须手动写死 header
Buffalo 从 v0.18.0 起就移除了 buffalo plugins 命令,所谓“CORS 中间件”全是误传。你不能写 app.Use(cors.Middleware),也不能依赖任何第三方插件——中间件链会在 handler 执行前调用 WriteHeader(),导致后续 Header().Set() 失效。
正确做法是:每个需要跨域的 handler 开头第一行,直接调用 c.Response().Header().Set()。顺序错了,header 就丢了,浏览器控制台里看不到 Access-Control-Allow-Origin,但不会报错,只会静默失败。
- 必须在
c.Render()、c.JSON()、c.Error()之前设置 - 不支持通配符
*配合Access-Control-Allow-Credentials: "true",否则浏览器拒绝请求 - 若前端带
withCredentials: true,后端必须同时设Access-Control-Allow-Credentials和明确的 origin(如"http://localhost:3000")
OPTIONS 预检路由必须显式注册并返回 200
浏览器发跨域请求前,会先发一个 OPTIONS 请求探路。Buffalo 不会自动处理它,你得自己注册一条路由,并确保它只设 header、不写 body、不调用 c.Render()。
示例写法(放在 routes/app.go 中):
app.Options("/api/*x", func(c buffalo.Context) error {
c.Response().Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
c.Response().Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
c.Response().Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization,X-Requested-With")
c.Response().Header().Set("Access-Control-Allow-Credentials", "true")
return nil // 注意:不是 c.Render(200, nil),也不能 return c.Render()
})
- 返回
nil即可,Buffalo 会默认返回 200;返回c.Render(200, nil)会触发WriteHeader(),再设 header 就无效 - 路径用
/api/*x可匹配所有子路径,但别用/*x匹配全局,避免暴露管理接口 - Safari 对非 200 的 OPTIONS 响应极其敏感,返回 204 或 404 会导致后续请求被静默拦截
多个域名需白名单比对,不能逗号分隔
Access-Control-Allow-Origin 不接受逗号分隔的多个域名(如 "http://a.com, http://b.com"),这是无效值,浏览器直接忽略。必须根据请求头里的 Origin 动态判断。
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
示例逻辑:
origin := c.Request().Header.Get("Origin")
allowedOrigins := map[string]bool{
"http://localhost:3000": true,
"https://prod.example.com": true,
}
if allowedOrigins[origin] {
c.Response().Header().Set("Access-Control-Allow-Origin", origin)
c.Response().Header().Set("Access-Control-Allow-Credentials", "true")
}
- 不要用
strings.Contains或模糊匹配,防止 origin 劫持(如evil.com/example.com) - 空
Origin(如本地 file:// 页面)或缺失时,建议跳过设置,不回退到* - 如果没匹配到任何 origin,别 fallback 到
*,否则带凭证的请求仍会失败
Access-Control-Allow-Headers 必须显式声明自定义字段
前端若在请求中加了 Authorization、X-Request-ID 等自定义 header,预检请求就会失败——除非你在 OPTIONS 和实际路由中都重复设置 Access-Control-Allow-Headers。
常见遗漏点:
-
Content-Type虽然常见,但仍是“自定义”范畴(除非是text/plain、multipart/form-data、application/x-www-form-urlencoded这三种浏览器原生允许的) -
X-Requested-With是 jQuery 默认加的,不声明它,AJAX 请求会卡在预检 - 大小写敏感:
authorization≠Authorization,必须严格按首字母大写拼写
真正容易被忽略的是:这个 header 得在 每一个非-OPTIONS 路由 handler 里再写一遍——和 OPTIONS 路由的设置完全独立,少一处,预检就挂。

















