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

后端 未结 4 1274
粉色の甜心
粉色の甜心 2020-12-17 10:22

Following This question i have set my rest controller behaviour as

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

    $auth= $behaviors         


        
相关标签:
4条回答
  • 2020-12-17 10:29

    Try This :

    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)
    
                    ],
                ],
    
            ]);
        }
    

    Add This Function on your controller .

    And One Thing angular2 use OPTION method at the first time For so allow OPTION method also

    0 讨论(0)
  • 2020-12-17 10:46

    The problem arises when the frontend runs in a port other than the default port (80).

    Then in yii you need to specify the port to work. Example: frontend runs at http: // localhost: 3000 in Yii cors set:

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

    If you do not specify the port (3000), Yii interprets the port by default and the result is:

    'Origin' => ['http: // localhost: 80']
    
    0 讨论(0)
  • 2020-12-17 10:48

    In case of any problems with CORS headers, I recommend to use following instruction:

    1. Add cors configuration to your controller. For instance:

      /**
       * 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. The above code will add to response special http-headers. Check http-headers using browser debug tools:

    3. Request http header should contain Origin. It will be added by browser automatically at Crossdomain AJAX. This http-header can be added also via your JS library. Without this http-header corsFilter won't work.

      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. Response http headers should contain Access-Control-* headers. This http-header will be added by 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. If you don't see these http headers in response, probably it means that \yii\filters\Cors doesn't work or conflicts with other filters.

    6. Check other behaviors/filters in controller. Try add corsFilter as first behavior. Probably some other behaviors prevents execution of corsFilter.

    7. Try to disable CSRF validation for this controller (it may prevent external access):

      /**
       * Controller for API methods.
       */
      class ApiController extends Controller
      {
      
          /**
           * @var bool See details {@link \yii\web\Controller::$enableCsrfValidation}.
           */
          public $enableCsrfValidation = false;
      
          // ...
      }
      
    8. If you are using authenticator filter (for example, your controller extends yii\rest\ActiveController) the CORS filter has to be applied BEFORE authentication methods. Also authentication has to be disabled for the CORS Preflight requests so that a browser can safely determine whether a request can be made beforehand without the need for sending authentication credentials.

      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;
      }
      
    9. Additionally should be checked your web-server. Probably nginx may require additional configuration, apache can require restarting.

    10. Access-Control-* headers in response can be added using web-server (see for apache and nginx). But I don't recommend to use this way, because in this case you can't manage http-haders using application.

    11. Some useful information can be found here:

      • Yii2: How to allow CORS on non-restfull API
    0 讨论(0)
  • 2020-12-17 10:48

    It is important to write $behaviors['access'] ie. AccessControl as a last parameter, for example:

    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   
                      ], 
                    ]   
        ];
      } 
    
    0 讨论(0)
提交回复
热议问题