跨域请求的解决方案(一)

跨域请求现在出现的频率越来越高,讨论一下其中一种方案。

实现方案

服务器端在响应体Header中添加Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Allow-Credentials、Access-Control-Max-Age

跨域的评判标准

首先看下一个网址的基本构成

http://www.xxx.com:4000/a.html
http 是协议
www.xxx.com 是域名
4000 是端口,http默认端口是80, https默认端口是443

  1. 协议不同 ( httphttps就算跨域)
  2. 域名不同 (a.baidu.comb.baidu.com 算跨域, 域名只要长得不一样都算跨域)
  3. 端口不同 (http://xxx.com:80http://xxx.com:8080 算跨域)

CROS-跨域资源共享

W3C标准:CROS,全称是跨域资源共享 (Cross-origin resource sharing),它的提出就是为了解决跨域请求的。

跨域资源共享(CORS)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

这是官方解释,有点绕,说白话就是,如果涉及跨域请求,浏览器会先发送一个OPTIONS请求检查下服务器是否允许跨域,如果返回的内容声明可以跨域,浏览器就会发送正式的请求。

发送预检请求的情况

这里要分两种请求类型:

  1. 简单请求(不发送预检)

    a. 请求方法为GET、POST、HEAD。
    b. HTTP的头信息不超出以下几种字段:

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
  2. 非简单请求

    不满足简单请求的任意一条就视为非简单请求

字段解释

  1. Access-Control-Allow-Origin (必需)
    服务器可以接受所有的请求源(Origin),设为 * 表示可以接受任意来源。

  2. Access-Control-Allow-Methods (必需)
    服务器支持的所有跨域请求的方法,用逗号分割。 如: GET,POST,PUT,OPTIONS

  3. Access-Control-Allow-Headers
    如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

  4. Access-Control-Allow-Credentials
    是否可以将对请求的响应暴露给页面。返回true则可以,其他值均不可以。当作为对预检请求的响应的一部分时,这表示是否真正的请求可以使用Credentials(Credentials可以是 cookies, authorization headers 或 TLS client certificates)。注意简单的GET请求没有预检,所以若一个对资源的请求带了credentials,如果这个返回这个资源,响应就会被浏览器忽视,不会返回到web内容。
    ps: Credentials必须在前后端都被配置(即服务端返回header中 Access-Control-Allow-Credentials 和 XHR 或Fetch request中都配置了)才能使带credentials的CORS请求成功。

  5. Access-Control-Max-Age
    指定本次预检请求的有效期,单位为秒。在缓存期间,不用发出另一条预检请求。

服务端处理示例

  1. 四个字段可以通过nginx、apache直接配置
    #nginx 配置示例
    location / {  
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
    } 
    #apache 配置示例
    NameVirtualHost 10.0.0.2:80
    
       DocumentRoot /var/www/host.example.com
       ServerName host.example.com
       Header set Access-Control-Allow-Origin "*"
       RewriteEngine on
       RewriteRule   ^/otherhost  http://otherhost.example.com/webapp [R,L]
    
  2. 在服务端代码逻辑中增加header
    //php 示例
    header('Access-Control-Allow-Origin:*); // *代表允许任何网址请求
    header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); // 允许请求的类型
    header('Access-Control-Allow-Credentials: true'); // 设置是否允许发送 cookies

发表评论

电子邮件地址不会被公开。 必填项已用*标注