yii2跨域预检需在请求进入业务逻辑前短路响应,否则鉴权等环节会报错;options 404因路由未注册,405因控制器未定义actionoptions或未跳过beforeaction;推荐用behavior前置拦截并设cors头后204终止,辅以url路由兜底或nginx层直接处理。

Yii2 处理跨域预检请求的核心,不是加个中间件完事,而是让 OPTIONS 请求在进入业务逻辑前就短路响应——否则鉴权、日志、模型加载等环节都可能报错或拖慢响应。
为什么 OPTIONS 总是 404 或 405?
Yii2 默认不注册 OPTIONS 动作,路由匹配失败就直接 404;即使路由通了,若控制器没定义 actionOptions(),或定义了但没跳过 beforeAction、没避开 $this->user 访问,就会因未认证抛异常,最终返回 405 或 500。这不是 CORS 配置没生效,是请求根本没走到 CORS 行为那一步。
用 Behavior 统一拦截(推荐做法)
在控制器的 behaviors() 方法中插入自定义行为,位置必须放在 AuthBearer、RateLimiter 等鉴权行为之前:
- 检查
Yii::$app->request->getMethod() === 'OPTIONS' - 设置必需头:
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers(注意与前端实际发送的 header 严格一致,比如含Authorization就必须写上) - 调用
Yii::$app->end(204)立即终止,不走后续流程
配合 URL 路由兜底
Behavior 只对已匹配到控制器的动作生效。若某接口路径完全没定义 OPTIONS 支持,请求连控制器都进不去。需在 urlManager 的 rules 中补一条显式规则:
-
'OPTIONS <strong>*</strong>' => 'site/options'(指向一个空控制器) - 或在 REST 模块中为每个 action 补
'extraPatterns' => ['GET,OPTIONS' => 'index'] - 确保
enablePrettyUrl已开启,否则 OPTIONS 请求可能被路由层直接忽略
Nginx 层提前拦截(高并发首选)
把 OPTIONS 响应从 PHP 层剥离,由 Nginx 直接处理,能显著减压:
- 在 server 或 location 块中写:
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Token'; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Max-Age 86400; add_header Cache-Control "public, max-age=86400"; return 204; } - Origin 必须动态回传(不能写死
*),尤其当启用了 credentials 时 - 确认 Nginx 未启用 UrlScan 或其他安全模块拦截 OPTIONS 方法











