2018-12-23 15:00:54 4401次浏览 4条回答 0 悬赏 100 金钱

这大概是跨越问题导致的
浏览器在发送 post 请求前会发一个 options 请求,如果失败就不会执行 post 请求。
我也设置了一些 header,但好像没什么用

$behaviors['corsFilter'] = [
    'class' => Cors::className(),
    'cors' => [
        // restrict access to
        'Origin' => ['127.0.0.1:80', 'http://127.0.0.1:3002', 'https://wxcwap.meikeyun.com'],
        // Allow only POST and PUT methods
        'Access-Control-Request-Method' => '*',
        // Allow only headers 'X-Wsse'
        // 'Access-Control-Request-Headers' => ['X-Wsse'],
        // Allow OPTIONS caching
        'Access-Control-Allow-Credentials' => null,
        // Allow the X-Pagination-Current-Page header to be exposed to the browser.
        // 'Access-Control-Max-Age' => 3600,
        // 'Access-Control-Expose-Headers' => ['X-Pagination-Current-Page'],
        'Access-Control-Expose-Headers' => [
            'Authorization',
            'X-Pagination-Current-Page',
            'X-Pagination-Page-Count',
            'X-Pagination-Per-Page',
            'X-Pagination-Total-Count'
        ],
    ],
];
$behaviors['authenticator'] = [
    'class' => CompositeAuth::className(),
    'optional' => $this->optional(),
    'authMethods' => [
        HttpBasicAuth::className(),
        HttpBearerAuth::className(),
        QueryParamAuth::className(),
    ],
];

最佳答案

  • 刘师傅 发布于 2018-12-23 19:20 举报

    这个简单,其实如果你的应用不是针对全世界广大群众的,那么就不用那么限制Origin。

    header('Access-Control-Allow-Origin:*');
    

    PHP这边只要把客户端需要的关键几个header准备好就行,无论是不是发送options请求都
    把这些header发送给客户端浏览器也无所谓,你可以把发送header的部分写到构造函数里。

    接下来就要判断是不是OPTIONS的请求,如果是,那就一个exit()搞定。你说呢?

    if (Yii::$app->getRequest()->getMethod() === 'OPTIONS') {
      exit;
    }
    

    上面这个,你不想执行action的话,那可以写到beforeAction里,你觉得呢?
    这样在options这一请求,浏览器永远会收到可以放行的信号;那么你只要做好token验证就行了。
    你觉得咋样?

    2 条回复
    回复于 2018-12-24 22:59 回复

    谢谢你的解答,我看了源码之后发现是配置项出错了,'Access-Control-Request-Method' => ['*'],这样就可以得到options返回200,'Access-Control-Request-Headers' => ['Authorization']这样就可以进行认证,但是我现在想知道另外一个优化方案,就是我的所有请求必须在verbs里配置支持OPTIONS才行,我觉得这样是不合理的,请问有什么好的办法吗

    `protected function verbs()

    {
        $verbs = parent::verbs();
        $verbs['register'] = ['POST'];
        $verbs['login-by-id'] = ['POST'];
        return $verbs;
    }`
    
    回复于 2018-12-24 23:40 回复

    这个问题我最终得到了几乎完美的解决方案,behaviors验证的时候有个顺序,只需要把corsFilter的顺序提前到verbFilter就可以在验证是否允许OPTIONS类型请求之前就返回200的成功码。

    PS:问这个问题还遇到一点波折,在一个YII群里问问题,结果有个自以为是的大佬一个劲的鄙视我,然后BB一大堆restful的知识,说我这api不是restful的,这这那那的。不管怎样吧,没帮上忙,还T我出群里,如果这个答案帮到你,希望大家能做一个谦虚一点的人,引以为耻。

    , 觉得很赞
  • 回答于 2018-12-24 10:29 举报

    beforeAction

  • 回答于 2018-12-25 09:40 举报

    beforeRequest也可以,这个拦截的更早

    1 条回复
    回复于 2018-12-25 10:22 回复

    不只是拦截,还得返回一些头信息,而这些头信息,所有请求都需要。

  • 回答于 2019-04-01 17:09 举报

    `

    namespace mycore\libs;

    use \Closure;
    use Yii;
    use yii\base\ActionEvent;
    use yii\base\Behavior;
    use yii\web\Controller;

    class CrossOriginBehavior extends Behavior
    {

    public $actions = [];
    
    public function events()
    {
        return [Controller::EVENT_BEFORE_ACTION => 'beforeAction'];
    }
    
    /**
     * @param $event
     * @return bool
     */
    public function beforeAction($event)
    {
        $action = $event->action->id;
        if(in_array($action, $this->actions)){
            // 指定允许其他域名访问
            //header('Access-Control-Allow-Origin:*');
            //header('Access-Control-Allow-Methods:POST,GET,OPTIONS'); //支持的http 动作
            //header('Access-Control-Allow-Headers:x-requested-with,content-type');
            $response = Yii::$app->getResponse();
            $response->getHeaders()->set('Access-Control-Allow-Origin', '*');
            $response->getHeaders()->set('Access-Control-Allow-Methods', 'POST,GET,OPTIONS');
            $response->getHeaders()->set('Access-Control-Allow-Headers', 'x-requested-with,content-type');
    
            //如果是OPTIONS操作,直接返回页面就可以,不需要返回具体业务信息
            if (Yii::$app->request->getMethod() == 'OPTIONS') {
                $response->data = 'options';
                $response->send();
                Yii::$app->end();
            }
    
            return true;
        }
    }
    

    }`

    在controll中应用
    ` public function behaviors()

    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'mod-avatar'=> ['POST','OPTIONS'],
                ],
            ],
            'CrossOriginBehavior' => [
                'class' => CrossOriginBehavior::className(),
                'actions' => [
                    'mod-avatar'
                ]
            ]
        ];
    }`
    
您需要登录后才可以回答。登录 | 立即注册
数字派
总监

数字派 北京

注册时间:2016-04-19
最后登录:2023-03-07
在线时长:52小时34分
  • 粉丝10
  • 金钱1515
  • 威望10
  • 积分2135

热门问题