如何配置Nginx代理服务器CORS,使React应用可访问Yii2 REST API
问题排查与解决方案
核心问题分析
你遇到的是部分API接口CORS正常、仅/v1/auth/login接口预检请求失败的问题,结合配置细节,根源大概率出在OPTIONS预检请求的处理逻辑、Yii2鉴权排除规则的准确性或CORS头的一致性配置上。
问题根源排查方向
- Nginx的CORS配置未覆盖OPTIONS请求:
login是POST请求,会触发浏览器的OPTIONS预检,若Nginx未针对OPTIONS请求返回完整CORS头,或配置的路由范围不包含/v1/auth/login,就会报错。 - Yii2的OPTIONS请求未被正确放行:虽然你排除了
login和options接口的JWT鉴权,但可能路由匹配规则有误,导致OPTIONS请求仍被鉴权拦截,返回的响应缺少CORS头。 withCredentials的头配置冲突:启用withCredentials后,Access-Control-Allow-Origin不能设为*,必须指定具体前端域名,若login接口的响应头不符合此规则,会触发错误。
分步解决方案
1. 修正Nginx的CORS配置,确保覆盖所有接口
在API的Nginx server块中添加完整的CORS规则,重点处理OPTIONS预检请求,同时保证所有请求都带上正确的头:
server { listen 443 ssl; server_name api.example.com; # 全局CORS头配置(必须加always,确保非200状态码也能返回头) add_header Access-Control-Allow-Origin "https://your-react-frontend.com" always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; add_header Access-Control-Allow-Credentials "true" always; # 直接处理OPTIONS预检请求,返回204(无需转发到Yii2) if ($request_method = OPTIONS) { return 204; } # Yii2入口路由配置 location / { try_files $uri $uri/ /index.php$is_args$args; # 其他fastcgi配置... } # 若login接口有单独location,需确保CORS头在此处也生效 # location /v1/auth/login { # add_header ... (同上CORS配置) # try_files $uri $uri/ /index.php$is_args$args; # } }
注意:Access-Control-Allow-Origin必须设置为你的前端实际域名,不能用*。
2. 确认Yii2鉴权与CORS过滤器配置
检查AuthController的behaviors()方法,确保OPTIONS请求和login接口被正确排除,同时启用Yii2的CORS过滤器(避免和Nginx配置冲突):
use yii\filters\Cors; use yii\filters\auth\HttpBearerAuth; public function behaviors() { $behaviors = parent::behaviors(); // 移除默认鉴权,替换为JWT鉴权 unset($behaviors['authenticator']); $behaviors['authenticator'] = [ 'class' => HttpBearerAuth::class, 'except' => ['login', 'options'], // 确保options和login动作被排除 ]; // 启用CORS过滤器,配置需和Nginx保持一致 $behaviors['corsFilter'] = [ 'class' => Cors::class, 'cors' => [ 'Origin' => ['https://your-react-frontend.com'], 'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], 'Access-Control-Allow-Credentials' => true, 'Access-Control-Max-Age' => 3600, ], ]; return $behaviors; }
验证:确保路由v1/auth/login对应的action是login,避免因路由映射错误导致鉴权未排除。
3. 验证Axios配置一致性
确保Axios全局配置的withCredentials为true,且请求域名与CORS头中的域名完全匹配:
import axios from 'axios'; axios.defaults.withCredentials = true; axios.defaults.baseURL = 'https://api.example.com/v1'; // 登录请求示例 axios.post('/auth/login', { username: 'your-username', password: 'your-password' }) .then(res => console.log(res)) .catch(err => console.error(err));
4. 测试预检请求
用curl手动发送OPTIONS请求到login接口,检查响应头是否包含正确的CORS字段:
curl -I -X OPTIONS https://api.example.com/v1/auth/login
正常响应应包含:
Access-Control-Allow-Origin: https://your-react-frontend.com Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

