设置跨域
yii2的跨域设置是非常便捷的,只需要设置 behaviors 中的 corsFilter 即可。
<?phpnamespace api\controllers;use common\web\CompositeAuth;use yii\filters\Cors;use yii\filters\auth\HttpBearerAuth;use yii\rest\Controller;/*** 基础校验控制** @author vogin**/class BasicController extends Controller{public function behaviors (){$behaviors = parent::behaviors();unset($behaviors['authenticator']);// 跨域设置$behaviors['corsFilter'] = ['class' => Cors::className()];// 校验 Authorization bearer$behaviors['authenticator'] = ['class' => CompositeAuth::className(),'authMethods' => [HttpBearerAuth::className()]];return $behaviors;}}
问题
但是,有时候,怎么配置都达不到效果出现报错
Access to XMLHttpRequest at ‘http://api.xxx.com‘ from origin ‘http://localhost:8080‘ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
问题1
权鉴在跨域之前被设置,比如这样。先是 $behaviors[‘authenticator’],再者 $behaviors[‘corsFilter’],这样会导致先鉴权再跨域,所以需要将设置提前,也就是 “设置跨域” 那样设置
<?phppublic function behaviors (){$behaviors = parent::behaviors();unset($behaviors['authenticator']);// 校验 Authorization bearer$behaviors['authenticator'] = ['class' => CompositeAuth::className(),'authMethods' => [HttpBearerAuth::className()]];// 跨域设置$behaviors['corsFilter'] = ['class' => Cors::className()];return $behaviors;}
问题2
路由问题。 由于并非继承 ActiveController,而是 yii\rest\Controll,所以路由都是自行指定的。 跨域检测是由 OPTIONS 方法去探测的,所以可能是此方法没有着落。 比如下面的方式,我并未指定 OPTIONS 对应的路由,所以其会报错
<?php'urlManager' => ['enablePrettyUrl' => true,'showScriptName' => false,'rules' => [// 获取所有标签'GET v1/tags' => 'v1/tag/all',// 获取单个标签'GET v1/tags/<id:\d+>' => 'v1/tag/one',// 添加单个标签'POST v1/tags' => 'v1/tag/add',// 编辑单个标签'PUT v1/tags' => 'v1/tag/edit',// 删除单个标签'DELETE v1/tags' => 'v1/tag/del',]],
解决此问题需要指定 OPTIONS,并且添加对应的方法
路由
<?php'urlManager' => ['enablePrettyUrl' => true,'showScriptName' => false,'rules' => [// options 检测'OPTIONS v1/tags' => 'v1/tag/options',]],
公共控制器中,增加 OPTIONS,有几个模块,加几次
<?php/*** 基础校验控制** @author vogin**/class BasicController extends Controller{public function actions (){return ['options' => ['class' => 'yii\rest\OptionsAction']];}// ......}
其他情况
那就直接在 index.php 的最上面把 php 跨域的代码写上
<?phpheader('Content-Type: text/html;charset=utf-8');header('Access-Control-Allow-Origin:*'); // *代表允许任何网址请求header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); // 允许请求的类型header('Access-Control-Allow-Credentials: true'); // 设置是否允许发送 cookiesheader('Access-Control-Allow-Headers: Content-Type,Content-Length,Accept-Encoding,X-Requested-with, Origin'); // 设置允许自定义请求头的字段
如何排查
断点
最好的排查方式就是打断点,OPTIONS 也是一个完整的请求,在idea上使用 xdebug 断点能快速调试
