iris v12+ 已移除内置 iris.cors(),需手写符合 iris.handler 签名的中间件:处理 options 预检、设置响应头(如 access-control-allow-origin)、调用 ctx.next();若带凭证,须指定白名单域名而非 *。

为什么 CORS 中间件在 Iris 里不能直接用 iris.CORS()
因为 Iris 官方从 v12 开始移除了内置的 iris.CORS() 函数,它不再提供开箱即用的 CORS 中间件。你如果照着旧文档或 Stack Overflow 示例写,会遇到 undefined: iris.CORS 错误。这不是你配置错了,是 API 已废弃。
正确做法是手动构造响应头,或使用社区维护的第三方中间件(如 rs/cors),但要注意兼容性 —— rs/cors 默认返回的是 http.Handler,而 Iris 的中间件签名是 iris.Handler(即 func(iris.Context))。
- 别试图 import
"github.com/kataras/iris/v12"后调用iris.CORS(),编译直接报错 - 不要把
rs/cors的cors.New(...).Handler直接传给app.Use(),类型不匹配 - 最轻量、最可控的方式是手写一个符合
iris.Handler签名的中间件
如何手写一个安全可用的 CORS 中间件
核心逻辑只有三步:预检请求(OPTIONS)直接放行、设置必要响应头、放行后续请求。不需要依赖外部包,也不用处理复杂策略(比如动态 origin 白名单),除非你真有那个需求。
下面是一个生产环境可用的最小实现:
func CORSMiddleware() iris.Handler {
return func(ctx iris.Context) {
ctx.Header("Access-Control-Allow-Origin", "*")
ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
ctx.Header("Access-Control-Allow-Headers", "Content-Type,Authorization,Accept,X-Requested-With")
ctx.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin")
if ctx.Request().Method == "OPTIONS" {
ctx.StatusCode(204)
return
}
ctx.Next()
}
}
-
Access-Control-Allow-Origin: "*"在有凭证(cookie / auth header)时会失效,此时必须指定具体域名,不能用通配符 - 如果接口要带 cookie,记得加
ctx.Header("Access-Control-Allow-Credentials", "true"),且Allow-Origin必须是明确域名(如https://example.com),不能是* -
OPTIONS返回204 No Content是标准做法,不是200,也不需要ctx.Stop()——return就够了
如何在路由组中启用并控制作用范围
中间件只对注册它的路由生效,这是优势也是易错点。如果你在 app.Use(CORSMiddleware()) 全局注册,所有路由都会带 CORS 头;但更常见的是只对 API 路由开放,比如 /api/ 下的所有接口。
推荐按路由组启用,避免静态资源(HTML/JS/CSS)也被加上不必要的头:
api := app.Party("/api")
api.Use(CORSMiddleware())
api.Get("/users", handlerGetUsers)
api.Post("/login", handlerLogin)
- 不要在
app.Use()里注册 CORS 后,又在某个Party里重复注册 —— 响应头会重复,部分浏览器可能拒绝请求 - 如果某些接口不允许跨域(比如管理后台内部调用),就不要把它们放进启用了 CORS 的路由组
- 调试时用
curl -I http://localhost:8080/api/users看响应头是否包含Access-Control-Allow-Origin,比前端报错更快定位问题
为什么本地开发用 * 没问题,上线后突然失败
因为浏览器对 Access-Control-Allow-Origin: "*" 和 Access-Control-Allow-Credentials: "true" 是互斥的。开发时前端可能没发 cookie,上线后登录态通过 withCredentials: true 发送,后端却还返回 *,浏览器直接拦截响应。
解决方法不是“修前端”,而是后端适配 origin:
func CORSMiddlewareWithOrigin(allowedOrigins []string) iris.Handler {
return func(ctx iris.Context) {
origin := ctx.GetHeader("Origin")
if len(origin) == 0 {
ctx.Next()
return
}
for _, o := range allowedOrigins {
if o == origin {
ctx.Header("Access-Control-Allow-Origin", origin)
break
}
}
ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
ctx.Header("Access-Control-Allow-Headers", "Content-Type,Authorization,Accept,X-Requested-With")
ctx.Header("Access-Control-Allow-Credentials", "true")
if ctx.Request().Method == "OPTIONS" {
ctx.StatusCode(204)
return
}
ctx.Next()
}
}
- 这个版本只在请求带
Origin头时才设Allow-Origin,避免无意义头污染 - 线上务必传入白名单,例如
["https://myapp.com", "https://admin.myapp.com"],别留空或硬编码"*" - 注意:Nginx 或其他反向代理可能剥离了
Origin头,检查proxy_set_header Origin $http_origin;是否存在
Origin 头的透传和预检请求的直通 —— 中间件再正确,上游把 OPTIONS 拦下来了,照样跨不过去。











