Yii CORS配置核心在于预检请求(OPTIONS)必须短路响应:需在urlManager中配置'OPTIONS *'路由指向空actionOptions(),禁用鉴权与输出,仅设头并调用Yii::$app->end(204)。

Yii 框架的 CORS 配置不是“加个中间件就完事”,核心问题在于:预检请求(OPTIONS)必须在鉴权、日志、控制器逻辑之前被短路响应,否则 404 或 headers already sent 错误几乎必然发生。
为什么直接配 Cors::className() 行为经常失效
这个行为只对已成功匹配到控制器 action 的请求起作用。而浏览器发起的预检请求,若对应 controller 没定义 actionOptions(),连控制器都不会进入,Cors 行为根本不会运行。
- 典型现象:前端发
PUT请求时控制台报错 “No 'Access-Control-Allow-Origin' header”,但GET正常——因为GET不触发预检,PUT触发了却没OPTIONS处理入口 - 路由层必须兜底:在
urlManager的rules中加一条'OPTIONS *' => 'site/options',指向一个空的SiteController::actionOptions() - 该
actionOptions()内不能调用$this->beforeAction()、不能访问$this->user、不能输出任何内容,只设头 +Yii::$app->end(204)
多域名 Origin 怎么安全支持
Access-Control-Allow-Origin 响应头不允许写多个值,也不能在 Origin 配置里同时用 ['*'] 和 'supportsCredentials' => true,否则浏览器直接拒绝。
- 正确做法:在
behaviors()的cors配置中,把'Origin'设为具体数组,如['https://a.com', 'https://b.net'] - 若需动态判断(比如从数据库查白名单),必须手动解析
Yii::$app->request->getHeaders()->get('Origin'),校验后用$response->setHeader('Access-Control-Allow-Origin', $origin)单写一个值 - Nginx 层不能靠
add_header Access-Control-Allow-Origin ...叠加多个,会触发 “multiple values” 错误并被浏览器拦截
用 Nginx 做反向代理时 OPTIONS 请求被吞了怎么办
默认情况下,Nginx 不会把 OPTIONS 请求透传给 PHP-FPM,而是自己处理或直接丢弃。
- 必须在 server 块中显式拦截:
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"; add_header Access-Control-Allow-Credentials "true"; add_header Access-Control-Max-Age "86400"; return 204; } - 注意:这段要放在
location ~ \.php$之前,否则不生效 - 如果用了
try_files,也要确保它不覆盖OPTIONS的提前返回逻辑
真正麻烦的不是怎么写配置,而是预检请求的生命周期和框架执行顺序——它必须绕过所有中间件和控制器初始化,否则哪怕头全对,也早就在 AuthBearer 或 RateLimiter 那一步被拦死了。











