编程技术文章分享与教程

网站首页 > 技术文章 正文

什么是预检请求,为什么POST请求会发送两次请求?

hmc789 2024-11-26 03:32:32 技术文章 2 ℃

在之前的分享中,我们提到了SpringBoot的跨域操作,在描述跨域操作的时候,我们提到了一个预检请求的概念,那么什么是预检请求呢?

什么是预检请求

所谓的预检请求(Preflight Request)其实就是在跨域操作中的提供的一个安全确认机制,用于在实际的操作请求之前去校验目标服务器是否允许进行跨域请求操作。这种预检请求是由浏览器端自动发出,主要的作用就是确保服务器端能够允许客户端进行某些跨域的请求操作。

具体操作方法,当浏览器执行一个跨域请求的时候,如果这个请求中使用了某些方法(例如 PUT、DELETE 或 PATCH)或者包含了一些自定义的头部字段(例如 Authorization),那么浏览器就会在发送正式的实际请求之前,先去发送一个HTTP OPTIONS请求,这个请求其实就是我们所说的预检请求,也是在面试过程中经常被问到的问题。

预检请求的目的就是确保跨域请求的安全性,就需要服务器在预检请求中确认是否允许跨域请求的执行。如果服务器端是允许这个跨域请求操作,那么它就会在预检请求的响应中包含适当的CORS头部字段,比如Access-Control-Allow-Origin、Access-Control-Allow-Methods和Access-Control-Allow-Headers等信息来允许跨域操作。

为什么 POST 请求会发送两次请求?

POST 请求并不总是会发送两次请求,只有在以下情况下才会发送两次请求。

  • 使用了非简单请求方法:简单请求方法包括GET、HEAD和POST,但POST请求如果包含了某些特殊的头部字段或内容类型(如application/json),则不再被视为简单请求。
  • 包含了自定义头部字段:如果请求中包含了一些浏览器默认不会发送的头部字段,比如Authorization。
  • 包含了非标准的内容类型:如果POST请求使用了除了application/x-www-form-urlencoded、multipart/form-data或text/plain之外的内容类型比如application/json。也就是说浏览器在这些请求情况下,会先发送一个预检请求,这样确定了服务器端允许相应的操作才开始发送相应的真实请求操作,如下所示。

举例说明

假设我们有一个前端应用要向https://example.com/api/data发送一个 POST 请求,包含JSON数据和Authorization头部,如下所示。

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

由于这个请求包含了Content-Type: application/json和Authorization头部,浏览器会先发送一个预检请求,如下所示。

OPTIONS /api/data HTTP/1.1
Host: example.com
Origin: http://your-origin.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization

服务器响应这个预检请求,如果允许跨域请求,会返回如下信息。

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://your-origin.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type, authorization

这个时候浏览器才会真正的发送一个POST请求进行调用。

这种机制可以有效的确保浏览器跨域请求的安全性,在一定程度上可以避免潜在的跨站请求伪造(CSRF)攻击等安全问题。

标签列表
最新留言