简单请求和复杂请求

282 阅读2分钟

在跨域资源共享(CORS,Cross-Origin Resource Sharing)机制中,HTTP 请求分为两类:简单请求(Simple Requests)和复杂请求(Preflighted Requests)。这两类请求有不同的处理方式和要求。

简单请求(Simple Requests)

简单请求指的是浏览器可以直接发送的请求,不需要额外的预检请求(preflight request)。这类请求的条件如下:

  1. 请求方法:请求方法必须是以下几种之一:

    • GET
    • HEAD
    • POST
  2. 请求头:请求头中只能包含以下几种头字段:

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID (仅限于 Server-Sent Events
    • Content-Type (仅限于以下值:application/x-www-form-urlencodedmultipart/form-datatext/plain
  3. 请求体:请求体的数据类型必须是 application/x-www-form-urlencodedmultipart/form-data 或 text/plain

示例:简单请求

javascript
fetch('https://api.example.com/data', {
  method: 'GET',
  headers: {
    'Accept': 'application/json'
  }
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

复杂请求(Preflighted Requests)

复杂请求指的是需要先发送一个预检请求(preflight request)来确认服务器是否允许跨域请求。预检请求是一个 OPTIONS 方法的请求,用于检查服务器是否允许后续的实际请求。

条件

如果请求不符合简单请求的条件,则被视为复杂请求。具体条件如下:

  1. 请求方法:除了 GETHEAD 和 POST 之外的方法,如 PUTDELETE 等。
  2. 请求头:请求头中包含除上述简单请求允许的头字段之外的其他头字段,如 AuthorizationContent-Type 等。
  3. 请求体:请求体的数据类型不是 application/x-www-form-urlencodedmultipart/form-data 或 text/plain

示例:复杂请求

javascript
fetch('https://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your-token-here'
  },
  body: JSON.stringify({ key: 'value' })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

预检请求(Preflight Request)

预检请求是一个 OPTIONS 方法的请求,用于确认服务器是否允许后续的实际请求。预检请求包含以下头字段:

  • Access-Control-Request-Method:实际请求的方法,如 PUTDELETE 等。
  • Access-Control-Request-Headers:实际请求中包含的自定义头字段。

示例:预检请求

http
OPTIONS /data HTTP/1.1
Host: api.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Origin: http://client.example.org

服务器响应预检请求时,应包含以下头字段:

  • Access-Control-Allow-Origin:允许的源。
  • Access-Control-Allow-Methods:允许的方法。
  • Access-Control-Allow-Headers:允许的头字段。
  • Access-Control-Max-Age:缓存预检结果的时间。

示例:预检请求的响应

http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

总结

  • 简单请求:直接发送请求,无需预检。
  • 复杂请求:先发送预检请求(OPTIONS),再发送实际请求。

通过合理配置服务器端的 CORS 设置,可以确保跨域请求的安全性和有效性。了解这两种请求的区别和处理方式,可以帮助开发者更好地处理跨域问题。