第53题 简单请求和复杂请求的区别

我们在日常的开发中,经常会遇到跨域资源共享,或者进行跨域接口访问的情况。跨域资源共享( CORS)机制允许 Web 应用服务器进行跨域访问控制。

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

在涉及到CORS的请求中,我们会把请求分为简单请求和复杂请求

1. 简单请求

满足以下条件的请求即为简单请求:

  • 请求方法:GETPOSTHEAD
  • 除了以下的请求头字段之外,没有自定义的请求头
  • Content-Type的值只有以下三种(Content-Type一般是指在post请求中,get请求中设置没有实际意义)
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器 (未验证)
    • XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
  • 请求中没有使用 ReadableStream 对象 (未验证)

2. 复杂请求

非简单请求即为复杂请求。复杂请求我们也可以称之为在实际进行请求之前,需要发起预检请求的请求。

简单请求与复杂请求的跨域设置

针对简单请求,在进行CORS设置的时候,我们只需要设置

    Access-Control-Allow-Origin:*
    // 如果只是针对某一个请求源进行设置的话,可以设置为具体的值
    Access-Control-Allow-Origin: 'http://www.yourwebsite.com'

针对复杂请求,我们需要设置不同的响应头。因为在预检请求的时候会携带相应的请求头信息

    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: X-CUSTOMER-HEADER, Content-Type

相应的响应头信息为:

    Access-Control-Allow-Origin: http://foo.example
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
    // 设置max age,浏览器端会进行缓存。没有过期之前真对同一个请求只会发送一次预检请求
    Access-Control-Max-Age: 86400

如果发送的预检请求被进行了重定向,那大多数的浏览器都不支持对预检请求的重定向。我们可以通过先发送一个简单请求的方式,获取到重定向的url XHR.responseURL,然后再去请求这个url

一般而言,对于跨域 XMLHttpRequestFetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位

如果在发送请求的时候,给xhr 设置了withCredentialstrue,从而向服务器发送 Cookies,如果服务端需要想客户端也发送cookie的情况,需要服务器端也返回 Access-Control-Allow- Credentials: true 响应头信息。

对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin的值为“*”

这是因为请求的首部中携带了Cookie信息,如果 Access-Control-Allow-Origin的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin的值设置为 http://foo.example(请求源),则请求将成功执行。

Last Updated:
Contributors: leeguooooo