Yii2中OPTIONS预检请求需在Nginx或框架入口前短路响应,避免进入MVC流程;推荐用Behavior统一拦截并立即返回204,确保置于鉴权行为之前,同时配准Access-Control-Allow-Headers与Origin策略。

Yii2 中 OPTIONS 请求被 404 或 405 拒绝怎么办
直接原因:Yii2 默认不注册 OPTIONS 动作,路由匹配失败或控制器没定义该动作,导致预检请求直接 404;或者虽有路由但没返回正确头,被浏览器判定为 CORS 失败。
关键不是“加个路由”,而是让框架在预检阶段就短路响应,不走完整 MVC 流程——否则容易触发鉴权、日志、中间件等副作用,还可能抛出未捕获异常。
- 确保
urlManager开启了enablePrettyUrl,否则OPTIONS可能根本进不了路由层 - 在控制器中显式声明
public function actionOptions(),并只做头设置 +exit或return $this->response - 避免在
actionOptions()里调用$this->beforeAction()或访问$this->user,预检时用户尚未认证,极易报错
用 behaviors() 统一处理所有接口的 CORS 预检
手动写每个控制器的 actionOptions() 易遗漏、难维护。更稳的方式是通过行为(Behavior)拦截所有请求,在入口前判断是否为 OPTIONS 并提前响应。
核心逻辑:在 behaviors() 中插入自定义行为,检查 Yii::$app->request->getMethod() === 'OPTIONS',满足则设置 Access-Control-Allow-Origin 等头,并调用 Yii::$app->end(204) 立即退出。
- 必须把该行为放在
AuthBearer、RateLimiter等鉴权/限流行为之前,否则预检会被拦住 -
Access-Control-Allow-Headers要严格匹配前端实际发的头(如Authorization,X-Requested-With),多一个少一个都会失败 - 若用 Nginx 做反向代理,注意它默认不透传
OPTIONS请求到 PHP —— 需显式配置if ($request_method = 'OPTIONS') { add_header ...; return 204; }
Cors 扩展的行为配置为什么有时不生效
Yii2 官方 yii\filters\Cors 行为本身没问题,但常见失效是因为它只控制“响应头”,不接管请求分发。当路由没匹配到任何 action 时,Cors 根本不会运行。
换句话说:这个行为只对“已成功进入控制器的动作”起作用;而预检请求常因没定义 actionOptions 导致连控制器都没进去,行为压根没机会执行。
- 必须配合路由规则兜底,例如在
urlManager的rules中加一条'<code>OPTIONS *' => 'site/options'(指向一个空控制器) -
Cors::className()的cors配置项中,'Origin'不要设成['*']同时又开启'Credentials',这会直接被浏览器拒绝 - 开发时用
curl -I -X OPTIONS http://api.example.com/v1/user直接测响应头,比刷页面看控制台更准
Nginx 层提前响应 OPTIONS 的边界情况
把预检拦截在 Web 服务器层最快,但只适用于静态跨域策略(即所有接口允许相同源、头、方法)。一旦需要动态判断 Origin(比如白名单校验),就必须交还给 PHP 处理。
典型翻车点:Nginx 返回了 204,但没带 Access-Control-Allow-Origin,或者带了但值是 * 而前端发了凭证请求(withCredentials: true)。
- 务必确认 Nginx 配置中
add_header Access-Control-Allow-Origin $http_origin;,而非硬编码* - 如果后端用了负载均衡或 CDN,注意它们可能缓存了
OPTIONS响应,导致头更新不及时 - Chrome 控制台 Network 标签下,预检请求的 “Headers” 面板里看不到
Access-Control-头?那基本可以断定是服务端根本没返回,而不是前端代码问题










