iris 必须显式注册 options 路由,因不自动捕获预检请求;仅中间件判断 options 无效,路由未匹配则中间件不执行;需配合 cors 中间件设置 access-control-allow-origin(白名单)、methods、headers 等头,并校验 origin。

Iris 没有内置 CORS 中间件,必须手动注册 OPTIONS 路由 + 自定义中间件组合生效,否则前端预检请求直接 404,根本进不到中间件逻辑里。
为什么必须显式注册 OPTIONS 路由?
Iris 不会自动捕获预检请求。如果你只在中间件里判断 ctx.Method() == "OPTIONS",但没在路由表中注册对应路径的 handler,Iris 就不会触发该中间件——因为路由未匹配,中间件压根不执行。
- 错误写法:
app.Use(corsMiddleware)后不注册任何OPTIONS路由 → 前端报错Response to preflight request doesn't pass access control check - 正确做法:对目标路径(如
/api/*)或通配符("*")显式调用app.Options() - 若 API 分组在
api := app.Party("/api")下,也得单独写api.Options("*", ...),不能只在根级注册
Cors 中间件要设哪些响应头?
只设 Access-Control-Allow-Origin 是不够的。带认证头(Authorization)、自定义 header(如 X-Auth-Token)或启用了 credentials: 'include' 的请求,会因缺少其他头被浏览器拦截。
- 必须设置:
Access-Control-Allow-Origin(生产环境禁用"*",需白名单校验)、Access-Control-Allow-Methods、Access-Control-Allow-Headers - 可选但推荐:
Access-Control-Expose-Headers(暴露给前端读取的响应头)、Access-Control-Max-Age(预检缓存时间) - 关键约束:
Access-Control-Allow-Credentials: "true"时,Access-Control-Allow-Origin不能为"*",必须是具体 origin(如"http://localhost:3000")
如何安全地处理 Origin 白名单?
Iris 不提供自动 origin 校验,全靠手写逻辑。硬编码白名单或完全放行都容易出问题。
- 开发环境可临时用
"*",但上线前必须替换为明确列表 - 建议从请求头读取
Origin,再比对预设 slice:allowedOrigins := []string{"https://example.com", "http://localhost:3000"} - 注意协议、端口、斜杠结尾都要一致;
https://example.com≠https://example.com/ - 若用
ctx.Request().Header.Get("Origin")获取,空值或非法值应返回 403,而不是默认放行
一个最小可用的 Cors 中间件示例
以下代码能跑通预检和实际请求,且避开常见坑:
func Cors(allowedOrigins []string) iris.Handler {
return func(ctx iris.Context) {
origin := ctx.Request().Header.Get("Origin")
if origin != "" {
// 白名单校验
allowed := false
for _, o := range allowedOrigins {
if o == origin {
allowed = true
break
}
}
if allowed {
ctx.Header("Access-Control-Allow-Origin", origin)
ctx.Header("Access-Control-Allow-Credentials", "true")
ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
ctx.Header("Access-Control-Allow-Headers", "Content-Type,Authorization,X-Auth-Token")
ctx.Header("Access-Control-Expose-Headers", "Content-Length")
ctx.Header("Access-Control-Max-Age", "172800")
} else {
ctx.StatusCode(403)
return
}
}
// OPTIONS 预检请求直接返回 204,不走后续 handler
if ctx.Method() == "OPTIONS" {
ctx.StatusCode(204)
return
}
ctx.Next()
}
}
// 注册方式(必须!)
app.Use(Cors([]string{"http://localhost:3000"}))
app.Options("*", func(ctx iris.Context) { ctx.StatusCode(204) })
注意:中间件里 ctx.Next() 前的 return 和 OPTIONS 的 204 状态码缺一不可;白名单校验逻辑必须放在中间件开头,避免 header 被污染或绕过。











