关于浏览器缓存预检请求的坑.......

209 阅读4分钟

问题描述

某天,哥们正高高兴兴初始化了项目后端服务器,测试是不是行了,结果一看报错了:

Access to XMLHttpRequest at '[http://127.0.0.1:7921/test](http://127.0.0.1:7921/test 
"http://127.0.0.1:7921/test")' from origin '[http://localhost:5173](http://localhost:5173/ 
"http://localhost:5173")' has been blocked by CORS policy: 
The value of the 'Access-Control-Allow-Credentials' header in the response is ''which must be 'true' when the request's credentials mode is 'include'. 
The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

看了看,哦正常,忘记给服务器配置跨域了。服务器是用Flask写的,于是高高兴兴下了一个flask_cors,稍微配置一下,设置supports_credentialsTrue,搞定!结果您猜怎么着,还是这个报错!

捏猫猫的,我怒了但是没什么用,找了一万年解决办法,问题还在,但是给一个接口单独上一个@cross_origin装饰器就又好了。于是我突然想到一个问题,打开postman一看,嘿,还真没问题,什么Access-Control-Allow-Credentials就是true了,于是突然想到了这个非常弱智的问题:不会是浏览器缓存吧...... 抱着死马当做活马医的态度,随手清了清缓存,结果,它还真好了沃日。

就此记录一下,浏览器的对预检请求的缓存是真的.......

预检请求

气氛都到这里了,介绍一下预检请求吧。

预检请求(Preflight Request)

预检请求是浏览器在发送某些类型的跨域请求之前自动发出的一种OPTIONS请求。它的目的是询问服务器当前请求是否安全,即确认实际请求是否可以安全地发送给目标服务器。这是浏览器为保护用户数据而实施的一种安全措施,确保只有当服务器明确允许时,才会发送可能对用户有风险的请求。

什么情况下会发出预检请求?

预检请求通常会在以下情况中被触发:

  1. 非简单请求方法:如果请求使用了除了GETHEADPOST之外的HTTP方法。
  2. 自定义请求头:如果请求中包含了自定义的HTTP头部信息(例如,添加了Authorization或自定义的安全令牌等)。
  3. Content-Type:对于POSTPUT请求,如果Content-Type不是下列之一:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

例如,如果你发送了一个带有application/json内容类型的POST请求,或者你添加了一个如X-Custom-Header这样的自定义请求头,浏览器将会首先发送一个预检请求。

预检请求的内容

预检请求是一个OPTIONS请求,它包含以下重要信息:

  • Access-Control-Request-Method: 实际请求将使用的HTTP方法。
  • Access-Control-Request-Headers: 实际请求中携带的自定义头部信息。
  • Origin: 发出请求的源(协议+域名+端口),用于跨域资源共享(CORS)检查。

服务器需要响应这些预检请求,并且必须包括相应的CORS头部来指示哪些资源可以被访问,以及允许哪些方法和头部。例如:

HTTP/1.1 200 OK
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:5173
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400  # 预检请求结果缓存的时间长度,单位为秒

浏览器是否会缓存预检请求?

浏览器会缓存预检请求的结果。这由服务器通过Access-Control-Max-Age头部控制,该头部指定了预检请求结果可以在浏览器中缓存多久(以秒为单位)。在这段时间内,浏览器不会再为相同的跨域请求发起新的预检请求。

例如,如果服务器返回Access-Control-Max-Age: 86400,则预检请求的结果将在接下来的24小时内被缓存。这意味着,在这段时间内,针对相同资源的所有符合条件的请求可以直接发送,无需再次进行预检。

这种机制有助于减少不必要的网络往返次数,从而提高性能,特别是对于频繁发生的跨域请求。然而,这也意味着如果你更新了服务器上的CORS策略,可能需要等待缓存过期或手动清除浏览器缓存才能看到变化。

但是问题又来了,我服务器也没设置这个Access-Control-Max-Age响应头呀,为什么预检请求的结果它就是被缓存了呢......