• 售前

  • 售后

热门帖子
入门百科

Yii支持多域名cors原理的实现

[复制链接]
水月花郎稳 显示全部楼层 发表于 2021-10-26 12:37:57 |阅读模式 打印 上一主题 下一主题
寻常我们遇到跨域问题时,常使用 cors(Cross-origin resource sharin)方式办理。不知你是否留意到,在设置相应头 Access-Control-Allow-Origin 域的值时,只答应设置一个域名,这意味着不能同时设置多个域名来共享资源。而在 Yii2 中直接使用
  1. 'Origin' => ['http://www.site1.com', 'http://www.site2.com']
复制代码
的情势却可以设置多个 cors 域名值,Why?

其实,Yii2 中采用了动态设置 Access-Control-Allow-Origin 域值的方法来办理这个问题。
  1. 说明:测试使用的接口域名[code]api.d.fanhaobai.com
复制代码
,cros 多域名为
  1. www.d.yii.com
复制代码
  1. www.fq.yii.com
复制代码
。[/code]
Nginx设置多域名

实行直接通过 Nginx 的
  1. add_header
复制代码
模块追加 Access-Control-Allow-Origin 值实现,如下:
  1. add_header Access-Control-Allow-Origin http://www.fq.yii.com;
  2. add_header Access-Control-Allow-Origin http://www.d.yii.com;
复制代码
接口 哀求 和 相应头 如下:
  1. Response Headers
  2. Access-Control-Allow-Origin: http://www.fq.yii.com
  3. Access-Control-Allow-Origin: http://www.d.yii.com
  4. Connection: keep-alive
  5. Content-Type: application/json; charset=UTF-8
  6. ... ...
  7. Request Headers
  8. Accept: */*
  9. Accept-Encoding: gzip, deflate
  10. Accept-Language: zh-CN,zh;q=0.8
  11. Host: api.d.fanhaobai.com
  12. Origin: http://www.fq.yii.com
  13. Proxy-Connection: keep-alive
  14. ... ...
复制代码
当前域为
  1. www.fq.yii.com
复制代码
,需跨域哀求
  1. http://api.d.fanhaobai.com/v1/config/list.json
复制代码
的资源。欣赏器抛出如下跨域错误:
  1. XMLHttpRequest cannot load http://api.d.fanhaobai.com/v1/config/list.json. The 'Access-Control-Allow-Origin' header contains multiple values 'http://www.fq.yii.com, http://www.d.yii.com', but only one is allowed. Origin 'http://www.fq.yii.com' is therefore not allowed access.
复制代码
以上信息明确分析,Access-Control-Allow-Origin 只能设置为一个值,即每次哀求只能对应一个域名值。故通过该方法不能设置多域名进行 cors。
Yii2设置多域名

Yii2 设置多域名 cors,只需在对应控制器(ConfigController)中设置 cors 行为,如下:
  1. class BaseController extends Controller
  2. {
  3.   /**
  4.    * @inheritdoc
  5.    */
  6.   public function behaviors()
  7.   {
  8.     return [
  9.       'corsFilter' => [
  10.         'class' => \yii\filters\Cors::className(),
  11.         'cors' => [
  12.           //运行cors域名列表
  13.           'Origin' => ['http://www.d.yii.com', 'http://www.fq.yii.com'],
  14.           'Access-Control-Allow-Credentials' => true,
  15.         ]
  16.       ],
  17.     ];
  18.   }
  19. }
复制代码
重新在
  1. www.fq.yii.com
复制代码
发送 cors 哀求,发现此时已经不存在跨域问题。相应头 如下:
  1. Access-Control-Allow-Credentials: true
  2. Access-Control-Allow-Origin: http://www.fq.yii.com
  3. Connection: keep-alive
  4. Content-Type: application/json; charset=UTF-8
  5. ... ...
复制代码
我们会发现,Access-Control-Allow-Origin 域的值为
  1. http://www.fq.yii.com
复制代码
,刚好为当前域名划一,且只有一个值,并未出现设置的
  1. http://www.d.yii.com
复制代码
值。
同时,在
  1. www.d.yii.com
复制代码
下发送 cors 哀求,也不存在跨域问题。相应头中 Access-Control-Allow-Origin 值为
  1. http://www.d.yii.com
复制代码

由此可知,Yii2 在控制器行为中设置 Origin 项,只是一个域名白名单,而返回的 Access-Control-Allow-Origin 同哀求的域名划一且在这个白名单中,这个 Access-Control-Allow-Origin 由 Yii2 根据当前哀求所在域名进行了动态处理。
Yii2动态Access-Control-Allow-Origin
查察 Yii2 的
  1. \yii\filters\Cors
复制代码
类源码,如下:
  1. class Cors extends ActionFilter
  2. {
  3.   /**
  4.    * @var array CORS所用的响应头
  5.    */
  6.   public $cors = [
  7.     'Origin' => ['*'],
  8.     'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
  9.     'Access-Control-Request-Headers' => ['*'],
  10.     'Access-Control-Allow-Credentials' => null,
  11.     'Access-Control-Max-Age' => 86400,
  12.     'Access-Control-Expose-Headers' => [],
  13.   ];
  14.   
  15.   /**
  16.    * 执行action前要做的事
  17.    * @inheritdoc
  18.    */
  19.   public function beforeAction($action)
  20.   {
  21.     $this->request = $this->request ?: Yii::$app->getRequest();
  22.     $this->response = $this->response ?: Yii::$app->getResponse();
  23.     ... ...
  24.     $requestCorsHeaders = $this->extractHeaders();
  25.     //获取cors所用的响应头
  26.     $responseCorsHeaders = $this->prepareHeaders($requestCorsHeaders);
  27.     //设置cors所用的响应头
  28.     $this->addCorsHeaders($this->response, $responseCorsHeaders);
  29.     return true;
  30.   }
  31.   
  32.   /**
  33.    * 处理cors所用的响应头,动态处理Access-Control-Allow-Origin域
  34.    * @param array $requestHeaders CORS headers we have detected
  35.    * @return array CORS headers ready to be sent
  36.    */
  37.   public function prepareHeaders($requestHeaders)
  38.   {
  39.     $responseHeaders = [];
  40.     //$requestHeaders['Origin']为源地址,请求所在域名
  41.     if (isset($requestHeaders['Origin'], $this->cors['Origin'])) {
  42.       //源地址在白名单中,则设置Access-Control-Allow-Origin为源地址
  43.       if (in_array('*', $this->cors['Origin']) || in_array($requestHeaders['Origin'], $this->cors['Origin'])) {
  44.         $responseHeaders['Access-Control-Allow-Origin'] = $requestHeaders['Origin'];
  45.       }
  46.     }
  47.     ... ...
  48.    }
  49. }
复制代码
主要头脑就是,查察源地点是否在 cors 白名单中,在则设置 Access-Control-Allow-Origin 域的值为源地点。这样就能满足 Access-Control-Allow-Origin 为一个值的限制,同时也能答应指定的域名进行 cors。
  1. 注意:使用该方法请确保 Nginx 配置中未操作 Access-Control-Allow-Origin 域。
复制代码
总结
通过 Nginx 设置 Access-Control-Allow-Origin 进行 cors,有且只能有一个特定域名,局限性较大。通过代码逻辑操作 Access-Control-Allow-Origin 来实现 cors,则比力机动,能办理多个域名进行 cors 的需求,但是如果接口非常,跨域设置则会失效。
以上就是本文的全部内容,盼望对各人的学习有所帮助,也盼望各人多多支持草根技能分享。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作