Yii2 cors 过滤错误 No 'Access-Control-Allow-Origin' header is present

Yii2 cors filters error that No 'Access-Control-Allow-Origin' header is present

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']);

现在有 cors 过滤器

    // 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 behaviors unset authenticator 中设置了 cors 过滤器并稍后添加,这可能是什么问题 我能错过什么

我也查看了This link and also this one 但是 none 解决了问题

试试这个:

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)

                ],
            ],

        ]);
    }

在您的控制器上添加此功能。

并且 Angular2 第一次使用 OPTION 方法因此也允许使用 OPTION 方法

如果 CORS headers 有任何问题,我建议使用以下指令:

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

    /**
     * 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)
                ],
            ],
    
        ]);
    }
    
  2. 上面的代码会添加到response special http-headers。使用浏览器调试工具检查 http-headers:

  3. 请求 http header 应包含 Origin。它将由浏览器自动添加到 Crossdomain AJAX。 http-header 也可以通过您的 JS 库添加。没有这个 http-header corsFilter 将无法工作。

    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
    
  4. 响应 http headers 应包含 Access-Control-* headers。 http-header 将由 corsFilter 添加。

    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
    
  5. 如果你没有看到这些http headers 响应,可能意味着\yii\filters\Cors不起作用或与其他过滤器冲突。

  6. 检查控制器中的其他 behaviors/filters。尝试添加 corsFilter 作为 第一个行为 。可能其他一些行为会阻止 corsFilter.

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

    /**
     * Controller for API methods.
     */
    class ApiController extends Controller
    {
    
        /**
         * @var bool See details {@link \yii\web\Controller::$enableCsrfValidation}.
         */
        public $enableCsrfValidation = false;
    
        // ...
    }
    
  9. 如果您使用 authenticator 过滤器(例如,您的控制器扩展 yii\rest\ActiveController),则 CORS 过滤器必须是 在身份验证方法 之前应用。此外,必须 为 CORS 预检请求禁用身份验证 以便浏览器可以安全地确定是否可以预先发出请求而无需发送身份验证凭据。

    use yii\filters\auth\HttpBasicAuth;
    
    public function behaviors()
    {
        $behaviors = parent::behaviors();
    
        // remove authentication filter
        $auth = $behaviors['authenticator'];
        unset($behaviors['authenticator']);
    
        // add CORS filter
        $behaviors['corsFilter'] = [
            'class' => \yii\filters\Cors::className(),
        ];
    
        // re-add authentication filter
        $behaviors['authenticator'] = $auth;
        // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
        $behaviors['authenticator']['except'] = ['options'];
    
        return $behaviors;
    }
    
  10. 另外应该检查一下你的web-server。可能 nginx 可能需要额外的配置,apache 可能需要 restarting.

  11. Access-Control-* header 可以使用 web-server 添加响应(参见 apache and nginx)。但我不建议使用这种方式,因为在这种情况下你无法管理 http-haders 使用 application.

  12. 一些有用的信息可以在这里找到:

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

然后在yii中需要指定端口才能工作。例子: 前端运行于 http: // localhost: 3000 在 Yii cors 集中:

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

如果不指定端口(3000),Yii默认解释端口,结果为:

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

写 $behaviors[[=​​13=]] 很重要,即。 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   
                  ], 
                ]   
    ];
  } 

我终于找到了这个问题的答案,而且可能是一个简单的答案,虽然这里回答的大部分内容都很好,但对我没有任何帮助,除非我真正理解正在发生的问题。

正如某些人所说的那样,浏览器倾向于在 pre-flight 中发送选项,因此请确保您的每个控制器(如果已定制)都能够处理选项请求,否则您将像我一样继续徘徊多年来,出了什么问题,我已经按照文档中的描述配置了所有内容,实现了每个人在网上所说的一切。

我只是在这里给你几个例子希望这会有所帮助,在实施了上面提到的所有解决方案之后仍然没有任何效果,除非我向我的控制器 actionOptions 添加了一个特定的功能,如下所示

    public function actionOptions() {
    $header = header('Access-Control-Allow-Origin: *');
}

以及 Yii 文档中描述的简单修改行为

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

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

    // add CORS filter
    $behaviors['corsFilter'] = [
        'class' => \yii\filters\Cors::class,
    ];

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

    return $behaviors;
}

这在我的 chrome 浏览器上非常有效。

现在,如果您设置了一些客户路线,就像我为我的一个控制器所做的那样

示例:

GET v1/users/profile You must set another route as OPTIONS v1/users/profile too.

最后但并非最不重要的一点是,在某些情况下,您的操作之一可能会被进一步自定义或仅使用标准操作,例如我的情况 actionIndex

我在该操作的顶部添加了 header,如下面的 actionIndex

  public function actionProfile() {
    $header = header('Access-Control-Allow-Origin: *');
    $profile = new \app\modules\v1\models\Profile();
    return $profile->prepare();
}

  public function actionIndex() {
    $header = header('Access-Control-Allow-Origin: *');
    $profile = new \app\modules\v1\models\Profile();
    return $profile->prepare();
}

我希望这对你们中的一些人有所帮助:)。