cors头不生效主因是options预检请求被认证过滤器拦截或中间件顺序错误:认证过滤器需排除options动作,cors中间件必须在认证前注册;凭据模式下origin不可用*而须显式列出源并设access-control-allow-credentials为true。

CORS 头没生效,多半是 corsFilter 放错了位置,或者被认证过滤器拦截了预检请求(OPTIONS)。
为什么 OPTIONS 请求总 401 或 403?
Yii 的认证过滤器(如 HttpBearerAuth、QueryParamAuth)默认会对所有动作生效,包括浏览器自动发出的 OPTIONS 预检请求。但预检请求不带认证头,直接被拦住,导致 CORS 头根本没机会发出去。
- 必须把
authenticator的except显式加上options:$behaviors['authenticator']['except'] = ['options']; - 或者更稳妥:先 unset
authenticator,再加corsFilter,最后把authenticator加回来,并设置except - 顺序不能错:
corsFilter必须在authenticator之前注册,否则认证失败就提前退出,CORS 头压根不写
Origin 设成 ['*'] 却仍报 credentials 错误?
当前端 AJAX 设置了 withCredentials: true(比如要传 cookie),后端就不能用通配符 Origin => ['*'],否则浏览器会直接拒绝响应。
- 必须显式列出允许的源,例如:
'Origin' => ['https://admin.example.com', 'http://localhost:3000'] - 同时必须设
'Access-Control-Allow-Credentials' => true(注意不是'true'字符串) -
'Access-Control-Allow-Credentials'设为null或false时,浏览器会忽略withCredentials,但前端收不到 cookie 或 auth header
Access-Control-Request-Headers 填 ['*'] 不安全还可能失效
虽然 Yii 默认值是 ['*'],但部分旧版浏览器(如 IE11、某些 Android WebView)不支持通配符,且 W3C 规范也明确说 Access-Control-Request-Headers: * 只在响应中有效,请求里不能这么写 —— 实际上这是个常见误解。
- 应明确列出前端真实发送的自定义头,例如:
['X-Requested-With', 'Authorization', 'X-Timezone'] - 如果用了
Content-Type: application/json,它属于“简单头”,无需额外声明;但Content-Type: text/plain就不行 —— 这类细节容易漏 - 调试时可临时开全:
'Access-Control-Request-Headers' => ['*'],上线前务必收紧
跨域后 POST/PUT 返回 405 Method Not Allowed?
这往往不是 CORS 问题,而是 URL 路由没配好 OPTIONS 方法。Yii RESTful 默认只响应 GET、POST 等,但不会自动处理 OPTIONS 动作,除非你显式配置。
- 检查
urlManager的rules,确保包含类似:'extraPatterns' => ['OPTIONS' => 'options'] - 或在控制器里加一个空的
actionOptions()方法(返回空响应即可) - 更推荐方式:用
yii\rest\UrlRule替代普通UrlRule,它内置支持OPTIONS
真正麻烦的从来不是加几行 cors 配置,而是预检请求(OPTIONS)和认证逻辑之间的时序竞争 —— 它不报错,只是静默失败,连 Network 面板都看不出头是否发出去了。











