前端涨薪功法:CORS策略中post为什么会发送两次请求?

1,163 阅读3分钟

CORS策略下,为什么Post请求会发送两次?

在前后端分离的Web应用中,我们常用CORS(跨域资源共享)策略来解决跨域问题。但是在使用CORS时,有些同学发现Post请求会发送两次,这篇博客就来分析原因以及解决方法。

CORS简介

CORS需要浏览器和服务器同时支持,关键步骤是:

  1. 浏览器发送预检请求,询问服务器是否允许跨域;
  2. 服务器响应,明确指出允许的方法和头信息;
  3. 浏览器确认可以跨域,发送真正的请求。

为什么会发送两次请求?

要启用CORS,需要服务器设置Access-Control-Allow-Origin等响应头。

如果未正确配置,第一次Post会触发预检请求:

POST https://api.example.com

// 预检请求
OPTIONS https://api.example.com

预检请求用于询问服务器是否允许跨域Post请求。如果服务器未响应,则浏览器阻止第二次Post发送。

配置响应头后,预检就通过了,浏览器就会发送第二次真实的Post请求。

所以 CORS 策略会导致 Post 需要发送两次请求。

如何避免两次请求?

要避免CORS发送两次请求,可以采取以下方法:

  1. 使用相同的域名和端口:CORS是跨域资源共享,因此如果你的前端代码和后端API位于相同的域名和端口下,就不会触发跨域请求,也就不会发送预检请求。这种情况下,POST请求只会发送一次。
  2. 配置服务器允许简单请求:CORS规范中规定了一些情况下的简单请求,不会触发预检请求。如果你的请求符合简单请求的条件,服务器可以配置响应头部信息,允许这些简单请求。简单请求的条件包括请求方法是GET、HEAD、POST之一,且请求头部只包含一些特定的字段,例如Accept、Accept-Language、Content-Language、Content-Type(只限于application/x-www-form-urlencoded、multipart/form-data、text/plain)等。通过配置服务器响应头部的Access-Control-Allow-Origin字段,允许请求的来源域,可以避免发送预检请求。
  3. 配置服务器允许特定的自定义请求头部:如果你的请求需要自定义头部信息,例如Authorization等,会触发预检请求。在服务器的响应头部信息中,添加Access-Control-Allow-Headers字段,指定允许的自定义头部信息列表,可以避免发送预检请求。
  4. 调整前端请求的头部信息:如果你有控制前端代码,可以尝试调整请求的头部信息,以使其符合简单请求的条件。例如,避免发送自定义的头部信息,或者使用合适的Content-Type值。

需要注意的是,上述方法只能在你有控制服务器端和前端代码的情况下实施。如果你无法更改服务器端的配置或者无法控制前端代码,可能需要与后端开发人员沟通,以寻找其他解决方案,例如使用代理服务器或者JSONP等技术手段来规避CORS问题。

服务器只要响应预检请求,明确指出允许跨域请求即可。

例如 Express可以这样配置:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Content-Type");
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  next(); 
});

配置好服务器响应跨域头后,预检就可以通过,浏览器会直接发送Post而不用两次请求。

考察点

基本的网络请求原理

总结

CORS策略会触发预检请求,如果服务器未正确响应,就会导致Post需要发送两次。这篇博客介绍了两次请求的根本原因,以及如何通过服务器端配置来避免这种情况。

希望这篇CORS的技术分析能帮助大家理解两次请求的根本原因,如果还有其他问题欢迎留言讨论!