iris 框架无内置 cors 中间件,需手动实现或引入第三方库,且必须显式注册 options 路由处理预检请求,否则返回 405;白名单校验、credentials 与 origin 冲突、静态资源路径拼写等细节极易导致跨域失败。

直接给结论:Iris 框架没有内置 CORS 中间件,必须手动写中间件或用第三方库(如 iris-contrib/middleware/cors),且 OPTIONS 预检请求必须显式注册,否则 405 错误必现。
为什么默认不生效?——Iris 不自动处理 OPTIONS
Iris 不像 Gin 那样在 CORSMiddleware 内部自动响应预检请求。当你前端发一个带 Authorization 或自定义 header 的请求时,浏览器会先发 OPTIONS,而 Iris 路由默认不匹配 OPTIONS /api/user 这类路径(除非你明确定义)。没匹配到就 404 或 405,跨域直接失败。
常见错误现象:
– 控制台报错 Response to preflight request doesn't pass access control check
– Network 面板里 OPTIONS 请求状态码是 405 Method Not Allowed
– 后端日志完全没打印该请求(说明根本没进路由)
- 必须为所有可能被跨域访问的路由组(如
/api)显式注册OPTIONS处理器,哪怕只是空处理 - 不能只靠中间件加 header 就完事;header 是响应头,但前提是请求得能进来
- 如果用了
Party分组,OPTIONS必须注册在同一个Party下,不能只挂在根路由上
怎么写一个安全可用的 CORS 中间件
手写中间件最可控,也最轻量。关键点是:区分预检请求和真实请求,对 OPTIONS 立即返回 204,不走后续逻辑。
示例代码(注意:不要无脑复制 "*"):
func Cors(ctx iris.Context) {
origin := ctx.GetHeader("Origin")
if origin == "" {
ctx.Next()
return
}
// 白名单校验(生产环境必须做)
allowedOrigins := []string{"https://your-frontend.com", "http://localhost:3000"}
isAllowed := false
for _, o := range allowedOrigins {
if origin == o {
isAllowed = true
break
}
}
if !isAllowed {
ctx.StatusCode(403)
return
}
ctx.Header("Access-Control-Allow-Origin", origin)
ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,PATCH,OPTIONS")
ctx.Header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
ctx.Header("Access-Control-Expose-Headers", "Content-Length, X-Total-Count")
ctx.Header("Access-Control-Allow-Credentials", "true") // 若需 cookie
if ctx.Method() == "OPTIONS" {
ctx.StatusCode(204)
return
}
ctx.Next()
}
-
Access-Control-Allow-Credentials: true和Access-Control-Allow-Origin: "*"互斥,必须指定具体 origin -
Access-Control-Expose-Headers是可选的,但如果你前端要读取响应里的X-Total-Count这类字段,就必须暴露 - 中间件注册顺序很重要:必须在
app.Use(Cors)之前注册recover等 panic 恢复中间件,否则 panic 时 CORS header 不会发出
用 iris-contrib/middleware/cors 的坑点
这个包封装了基础逻辑,但默认配置仍不够生产就绪:
- 它默认允许
"*",但一旦设了AllowCredentials: true,就会 panic 报错credentials flag is true, but Access-Control-Allow-Origin is set to "*" - 它的
MaxAge默认是 0,每次预检都要重发,影响性能;建议设成86400(24 小时) - 它不自动注册
OPTIONS路由,仍需手动补一句app.Options("/api/*", iris.NoHandler)或类似逻辑 - 若你用的是
v12版本,注意导入路径是github.com/kataras/iris/v12/middleware/cors,不是旧版v11的路径
最后检查项:别漏掉静态资源路径
前端打包后常通过 /assets/xxx.js 加载资源,如果这些路径也被 CAS、Nginx 或反向代理拦截并跳转,就会触发二次跨域(比如从 https://fe.com → https://cas.com/login),此时浏览器控制台报错不是 CORS,而是 net::ERR_BLOCKED_BY_CLIENT 或跳转 302。
排查方式:
– 在 Chrome DevTools 的 Network 标签页里,筛选 Initiator 是 other 的请求,看是否意外跳转
– 检查 Nginx 配置或 web.xml(如知识库中提到的 assests 拼写错误)
– 确保 /assets、/static 等路径在 Iris 中被 app.HandleDir 正确托管,且未被中间件误拦截
真正容易被忽略的,是 OPTIONS 请求的路由注册位置和静态资源路径的拼写一致性 —— 这两个地方出错,连中间件都压根没机会执行。











