跨域问题解决方案:CORS(跨域资源共享)

0 阅读4分钟

CORS(Cross-Origin Resource Sharing,跨域资源共享)是一种基于HTTP1.1的跨域解决方案,它允许浏览器在满足一定条件下跨域访问服务器资源。本文将详细介绍CORS的原理、三种请求模式以及如何在实际开发中使用CORS。

一、CORS的基本原理

CORS的核心思想是:如果浏览器要跨域访问服务器的资源,需要获得服务器的允许。服务器通过在响应头中添加特定的字段来告知浏览器是否允许跨域访问。这些字段包括:

  • Access-Control-Allow-Origin:指定允许访问该资源的外域URL,或者使用*表示允许任何外域访问。
  • Access-Control-Allow-Methods:指定允许使用的HTTP方法。
  • Access-Control-Allow-Headers:指定允许的请求头字段。
  • Access-Control-Allow-Credentials:指定是否允许发送Cookie。
  • Access-Control-Max-Age:指定预检请求的结果可以被缓存的时间(秒)。
  • Access-Control-Expose-Headers:指定允许浏览器访问的额外响应头字段。

二、CORS的三种请求模式

CORS规定了三种不同的交互模式,分别是简单请求、需要预检的请求和附带身份凭证的请求。这三种模式从上到下层层递进,请求可以做的事越来越多,要求也越来越严格。

(一)简单请求

简单请求是最常见的一种跨域请求模式。当请求同时满足以下条件时,浏览器会认为它是一个简单请求:

  1. 请求方法属于以下之一:
    • GET
    • POST
    • HEAD
  2. 请求头仅包含安全的字段,常见的安全字段如下:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  3. 请求头如果包含Content-Type,仅限以下值之一:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

如果以上三个条件同时满足,浏览器判定为简单请求。例如:

// 简单请求
fetch('http://crossdomain.com/api/news');

对于简单请求,浏览器会在请求头中自动添加Origin字段,告知服务器请求的源地址。服务器响应时,需要在响应头中添加Access-Control-Allow-Origin字段,告知浏览器是否允许该请求跨域访问。例如:

HTTP/1.1 200 OK
Date: Tue, 21 Apr 2020 08:03:35 GMT
...
Access-Control-Allow-Origin: http://my.com
...

(二)需要预检的请求

如果请求不满足简单请求的条件,浏览器会发送一个预检请求(OPTIONS请求),询问服务器是否允许后续的真实请求。预检请求的流程如下:

  1. 浏览器发送预检请求,询问服务器是否允许

    预检请求的特征如下:

    • 请求方法为OPTIONS
    • 请求头中包含OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段

    例如:

    // 需要预检的请求
    fetch('http://crossdomain.com/api/user', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
      },
      body: JSON.stringify({ name: '袁小进', age: 18 }),
    });
    

    预检请求如下:

    OPTIONS /api/user HTTP/1.1
    Host: crossdomain.com
    ...
    Origin: http://my.com
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: content-type
    
  2. 服务器响应预检请求

    如果服务器允许该请求,需要在响应头中添加以下字段:

    • Access-Control-Allow-Origin:允许的源
    • Access-Control-Allow-Methods:允许的请求方法
    • Access-Control-Allow-Headers:允许的请求头字段
    • Access-Control-Max-Age:预检请求的结果可以被缓存的时间(秒)

    例如:

    HTTP/1.1 200 OK
    Date: Tue, 21 Apr 2020 08:03:35 GMT
    ...
    Access-Control-Allow-Origin: http://my.com
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Headers: content-type
    Access-Control-Max-Age: 86400
    ...
    
  3. 浏览器发送真实请求

    预检请求通过后,浏览器会发送真实请求。真实请求的处理与简单请求相同。

(三)附带身份凭证的请求

默认情况下,跨域请求不会附带Cookie。如果需要附带Cookie,可以通过配置实现。附带身份凭证的请求需要在请求头中添加Cookie字段,服务器响应时需要明确告知客户端允许这样的凭据。例如:

// 附带身份凭证的请求
fetch('http://crossdomain.com/api/user', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
  },
  body: JSON.stringify({ name: '袁小进', age: 18 }),
  credentials: 'include',
});

服务器响应时,需要在响应头中添加Access-Control-Allow-Credentials: true字段。例如:

HTTP/1.1 200 OK
Date: Tue, 21 Apr 2020 08:03:35 GMT
...
Access-Control-Allow-Origin: http://my.com
Access-Control-Allow-Credentials: true
...

总结

CORS是一种基于HTTP1.1的跨域解决方案,它通过在请求和响应头中添加特定的字段来实现跨域资源共享。CORS规定了三种请求模式:简单请求、需要预检的请求和附带身份凭证的请求。通过合理配置服务器和前端代码,可以有效地解决跨域问题,从而提高Web应用的可用性和安全性。