浏览器预检请求

在 web 开发时遇到 preflight CORS 跨域错误,如下图所示,这是什么鬼?

所谓 preflight CORS,就是在使用跨域请求时,浏览器会先发送一个预检请求,也被称为 OPTIONS 请求,来确认服务器是否支持特定的请求方法、请求头、以及是否允许跨域请求。

本文来分析分析这个预检请求到底有啥用,以及为什么会出现跨域失败的情况。

什么是预检请求?

预检请求是浏览器在发送跨域请求时,在正式请求之前,向服务器发送的一个 HTTP OPTIONS 请求。预检请求的主要目的是为了确定服务器是否支持特定的请求方法、请求头、以及是否允许跨域请求。预检请求的响应中包含了支持的请求方法、请求头以及是否允许跨域请求的信息,如果服务器支持这些请求,则浏览器才会发送真正的请求。

所以,如果出现预检请求跨域失败的情况,一般可以通过以下几个方面进行排查:

  • 服务端是否支持预检请求;
  • 服务端是否支持特定的请求方法、请求头、以及是否允许跨域请求。
  • 服务端是否正确返回了预检请求的响应。

为什么要有预检请求?

在 Web 开发中,由于浏览器的同源策略限制,跨域请求是一个很常见的问题。如果没有预检请求,浏览器就不能确定服务器是否支持特定的请求方法、请求头、以及是否允许跨域请求。这时浏览器会发出一个简单请求(比如 GETPOST 请求),服务器会拒绝该请求并返回错误信息。为了解决这个问题,引入了预检请求机制,用来确认服务器是否支持跨域请求,并根据响应信息决定是否发送真正的请求。

触发预检请求的条件

当满足以下条件时,浏览器会触发预检请求:

1、请求方法不是 GETHEADPOST 中的一种;

2、只能使用安全的请求头;

请求头说明
Accept指定客户端能够接收的内容类型
Accept-Language指定客户端能够接收的语言
Content-Language指定请求体中的语言
DPR指定设备的像素比
Downlink指定设备的下行速度
Save-Data指定是否启用节省数据模式
Viewport-Width指定设备的视口宽度
Width指定设备的屏幕宽度
Content-Type指定请求体的内容类型,只能使用 application/x-www-form-urlencodedmultipart/form-datatext/plain 中的一种

3、发送的请求数据是不可序列化的数据类型,比如 BlobFile 等。

预检请求的响应

当浏览器发送预检请求时,服务器需要返回以下信息:

  • Access-Control-Allow-Origin:指定允许跨域访问的域名;
  • Access-Control-Allow-Methods:指定允许的 HTTP 方法;
  • Access-Control-Allow-Headers:指定允许的请求头;
  • Access-Control-Allow-Credentials:指定是否允许发送 Cookie;
  • Access-Control-Max-Age:指定响应缓存时间。

如果服务器返回的信息不符合要求,浏览器将不会发送真正的请求,而是返回一个错误信息。

预检请求的缓存

由于预检请求的响应信息是不变的,所以可以进行缓存。服务器可以在响应中添加 Access-Control-Max-Age 头信息,来指定响应的缓存时间,避免重复发送预检请求。

预检请求的限制

预检请求可能会对性能产生一定的影响,因为每次跨域请求都需要发送一个额外的预检请求。为了避免这个影响,可以通过以下几个方面进行优化:

  1. 使用简单请求:对于满足条件的请求(请求方法为 GETHEADPOST,没有自定义请求头),可以使用简单请求来避免预检请求。
  2. 减少跨域请求:尽量减少跨域请求的次数,可以通过将静态资源放在同一域名下,或者使用 CDN 来提高性能。
  3. 缓存预检请求的响应:可以使用 Access-Control-Max-Age 头信息来缓存预检请求的响应,避免重复发送预检请求。
  4. 减少请求头的使用:尽量减少使用自定义请求头,避免触发预检请求。

结语

预检请求是解决跨域请求的一个重要机制,它可以确保浏览器发送的请求是安全的,并且服务器也能够正确地处理这些请求。预检请求虽然会对性能产生一定的影响,但可以通过减少跨域请求、缓存预检请求的响应、减少请求头的使用等方式进行优化,提高性能。合理的使用预检请求,可以帮助我们更好地解决跨域请求的问题。

如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注