Yii2 cors过滤错误,表示没有'Access-Control-Allow-Origin'标头

时间:2017-01-14 06:32:53

标签: php angular yii2 yii2-advanced-app

关注This question我已将我的休息控制器行为设置为

public function behaviors()
{
    $behaviors = parent::behaviors();

    $auth= $behaviors['authenticator'] = [
        'class' => HttpBearerAuth::className(),
        'only' => ['dashboard'],
    ];
    $behaviors['contentNegotiator'] = [
        'class' => ContentNegotiator::className(),
        'formats' => [
            'application/json' => Response::FORMAT_JSON,
        ],
    ];
    $acces=$behaviors['access'] = [
        'class' => AccessControl::className(),
        'only' => ['login'],
        'rules' => [
            [
                'actions' => ['login'],
                'allow' => true,
                'roles' => ['?'],
            ],
        ],
    ];

    unset($behaviors['authenticator']);
    unset($behaviors['access']);

现在可以过滤

    // add CORS filter
    $behaviors['corsFilter'] = [
        'class' => \yii\filters\Cors::className(),
          'cors' => [
        // restrict access to
        'Access-Control-Allow-Origin' => ['*'],
        'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
        // Allow only POST and PUT methods
        'Access-Control-Request-Headers' => ['*'],
        // Allow only headers 'X-Wsse'
        'Access-Control-Allow-Credentials' => true,
        // Allow OPTIONS caching
        'Access-Control-Max-Age' => 86400,
        // Allow the X-Pagination-Current-Page header to be exposed to the browser.
        'Access-Control-Expose-Headers' => [],
      ]
    ];

    // re-add authentication filter
    $behaviors['authenticator'] = $auth;
       $behaviors['access'] = $access;
    // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
    $behaviors['authenticator']['except'] = ['options'];
    return $behaviors;
}

我的angular2前端

    const body = JSON.stringify(user);
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Content-Type', 'application/json');
headers.append('Access-Control-Allow-Credentials', "*");
return this._http.post(this.loginUrl, body, { headers:headers })
  .map((response: Response) => {
     //process response
  })
.catch(this.handleError);

但我仍然收到错误

Response to preflight request doesn't pass access control check: No
 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 
 'http://localhost:3000' is therefore not allowed access.

因为我在yii2行为中设置了cors过滤器而未设置身份验证器并稍后添加它,所以可能出现了什么问题 我可以错过什么

我还检查了This linkthis one  但没有人解决问题

4 个答案:

答案 0 :(得分:7)

如果CORS标题出现任何问题,我建议使用以下说明:

  1. 将cors配置添加到控制器。例如:

    SELECT * FROM booking WHERE userid='67' AND (STR_TO_DATE(`bookingfrom`, '%d-%m-%Y') <='2017-02-24' AND (STR_TO_DATE(`bookingtill`, '%d-%m-%Y') >='2017-02-24')) AND service='test' AND status='0'
    
  2. 以上代码会将添加到响应特殊的http-header。使用浏览器调试工具检查http-header:

  3. 请求http标头应包含/** * List of allowed domains. * Note: Restriction works only for AJAX (using CORS, is not secure). * * @return array List of domains, that can access to this API */ public static function allowedDomains() { return [ // '*', // star allows all domains 'http://test1.example.com', 'http://test2.example.com', ]; } /** * @inheritdoc */ public function behaviors() { return array_merge(parent::behaviors(), [ // For cross-domain AJAX request 'corsFilter' => [ 'class' => \yii\filters\Cors::className(), 'cors' => [ // restrict access to domains: 'Origin' => static::allowedDomains(), 'Access-Control-Request-Method' => ['POST'], 'Access-Control-Allow-Credentials' => true, 'Access-Control-Max-Age' => 3600, // Cache (seconds) ], ], ]); } 。它将由浏览器自动添加到Crossdomain AJAX。这个http-header也可以通过你的JS库添加。没有这个http-header Origin就不会工作。

    corsFilter
  4. 响应http标头应包含POST /api/some-method-name HTTP/1.1 Host: api.example.com Connection: keep-alive Content-Length: 86 Accept: */* Origin: https://my-site.example.com User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Referer: https://my-site.example.com/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,ru;q=0.4 标头。此http-header将由Access-Control-*添加。

    corsFilter
  5. 如果您没有看到这些http标题作为回应,则可能意味着HTTP/1.1 200 OK Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: https://my-site.example.com Content-Type: application/json; charset=UTF-8 Date: Fri, 24 Feb 2017 09:21:47 GMT Server: Apache Content-Length: 27 Connection: keep-alive 无法正常工作。

  6. 检查控制器中的其他行为/过滤器。尝试将\yii\filters\Cors添加为第一个行为。可能某些其他行为会阻止执行corsFilter

  7. 尝试禁用此控制器的CSRF验证(可能会阻止外部访问):

    corsFilter
  8. 另外应检查您的网络服务器。可能nginx可能需要额外的配置,apache可能需要重新启动

  9. 可以使用Web服务器添加
  10. /** * Controller for API methods. */ class ApiController extends Controller { /** * @var bool See details {@link \yii\web\Controller::$enableCsrfValidation}. */ public $enableCsrfValidation = false; // ... } 响应中的标头(请参阅apachenginx)。但我不建议使用这种方式,因为在这种情况下,您无法使用应用程序管理http-haders。

  11. 可在此处找到一些有用的信息:

答案 1 :(得分:4)

试试这个:

public static function allowedDomains()
{
    return [
        // '*',                        // star allows all domains
        'http://localhost:3000',
        'http://test2.example.com',
    ];
}  



public function behaviors()
    {
        return array_merge(parent::behaviors(), [

            // For cross-domain AJAX request
            'corsFilter'  => [
                'class' => \yii\filters\Cors::className(),
                'cors'  => [
                    // restrict access to domains:
                    'Origin'                           => static::allowedDomains(),
                    'Access-Control-Request-Method'    => ['POST'],
                    'Access-Control-Allow-Credentials' => true,
                    'Access-Control-Max-Age'           => 3600,                 // Cache (seconds)

                ],
            ],

        ]);
    }

在控制器上添加此功能。

并且One Thing angular2在第一次使用OPTION方法因此允许OPTION方法

答案 2 :(得分:1)

当前端在默认端口(80)以外的端口中运行时,会出现此问题。

然后在yii中,您需要指定要使用的端口。例: 前端运行在http: // localhost: 3000 在Yii cors中设置:

'Origin' => ['http: // localhost: 3000']

如果您未指定端口(3000),则Yii默认会解释该端口,结果为:

'Origin' => ['http: // localhost: 80']

答案 3 :(得分:0)

写$ behaviors ['access']即。 AccessControl作为最后一个参数,例如:

public function behaviors()     {
    $behaviors = parent::behaviors(); 

    // remove authentication filter         
    unset($behaviors['authenticator']);   

    $behaviors['corsFilter'] = [     
        'class' => \yii\filters\Cors::class,
        'cors'  => [
                'Origin' => ['*'], 
                'Access-Control-Request-Method'    => ['POST', 'GET', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'], 
                'Access-Control-Allow-Headers' => ['Origin', 'X-Requested-With', 'Content-Type', 'accept', 'Authorization'], 
                'Access-Control-Request-Headers' => ['*'],    
                'Access-Control-Max-Age'           => 3600, // Cache (seconds) 
                // Allow the X-Pagination-Current-Page header to be exposed to the browser.             
                'Access-Control-Expose-Headers' => ['X-Pagination-Total-Count', 'X-Pagination-Page-Count', 'X-Pagination-Current-Page', 'X-Pagination-Per-Page'] 
        ] 
    ];           

    $behaviors['authenticator'] = [ ... whatever ... ];          

    $behaviors['access'] = [           
      'class' => AccessControl::className(),           
      'rules' => [   
                  [  
                    'allow' => true,   
                    'actions' => ['options'], // important for cors ie. pre-flight requests   
                  ], 
                ]   
    ];
  }