缓存CORS,减少不必要的请求

2024-04-07 10:19:17

阅读:302
标签:node

缓存CORS,减少不必要的请求

对于许多API来说,CORS是必需的,但是默认的配置可能会创建大量额外请求,降低浏览器请求API的速度

对于传统API服务来说,这可能仅仅是一个问题,但对于使用云服务器的问题更加严重,因为通常这些云服务是按流量收费的,因此这很容易使API成本增加

本文我们试图减少这些不必要的请求

CORS 预检请求

在浏览器发出任何跨域的请求之前,如果它不是一个简单的请求,那么浏览器首先发送一个预发送请求,并在发送真正的请求之前等待一个成功的响应

这个预请求是对服务器的OPTIONS请求,描述浏览器想要发送的请求,并首先请求权限。大概长这样:

  OPTIONS /v1/health
  Host: https://api.baidu.com
  Origin: https://baidu.com
  Access-Control-Request-Method: PUT
  Access-Control-Request-Headers: origin, x-requested-with

服务器必须用给出响应,以确认它接受用户请求,而浏览器则端等待响应后发送真正的请求
几乎所有跨域 API 请求都需要这些预请求,特别是包括:

  1. body带有 JSON 或 XML 请求
  2. 证书请求
  3. 不是 GET、POST 或 HEAD 的请求
  4. 流式传输请求
  5. headers不包含Accept, Accept-Language, Content-Language and Content-Type之外的请求

为什么要处理它

  • 增加请求时间,每个请求至少需要等待一个往返服务器时间,才会发出真实请求
  • 默认情况下OPTIONS 请求是不被缓存的,CDN 通常也不会处理它们
  • 客户端中缓存默认情况下仅缓存 5 秒,如果你有一个网页轮询API,每10秒发出一次请求,它们也会每10秒重复一次预请求
  • 从最终用户的角度来看,几百毫秒的延迟会影响转化率和用户满意度
  • 增加 API 服务器额外负载和成本
  • 增加流量费用

如何缓预请求响应

有两个缓存步骤:

  • 在浏览器中缓存,这样客户端就不会重复相同预请求

  • 在可能的情况下缓存在你的 CDN 层中,这样你的后端服务器就不必处理它们了

浏览器 CORS 缓存

要在浏览器中缓存CORS响应,只需要在请求头中加上:

  Access-Control-Max-Age: 86400

这是以秒为单位的缓存时间

不同浏览器对此进行了限制:Firefox 将值上限为 86400(24 小时),而 Chromium 内核的浏览器上限为 7200(2 小时)。即使是2个小时也会提高我们的用户体验和降低流量成本,通常我们会将这个时间设置成最高以适应更长的生命周期

CDN 的 CORS 缓存

在浏览器和 API 服务器之间的 CDN 层或其他代理中缓存 CORS 响应,添加:

  Cache-Control: public, max-age=86400
  Vary: origin

这将设置公共缓存为24小时,这对于大多数情况应该足够,而不会有缓存失效的风险。对于测试情况,你可以将缓存时间设置得更短一些,并在测试通过后设置增加缓存时间

需要注意的是,这并不是标准的做法(默认情况下OPTIONS被定义为不可缓存),但它似乎得到了大多数cdn的广泛支持,他们很乐意缓存像这样显式选择加入的OPTIONS响应。有些可能需要手动启用此功能,因此请在配置中测试此功能

在最坏的情况下,如果你的 CDN 不支持它,它将被忽略,因此没有真正的缺点

这里的Vary标头很重要:这告诉缓存除了使用相同的 URL 之外,仅对具有相同Origin标头的其他请求也使用此响应。如果不设置Vary头文件,就会出现大问题。预请求通常包括一个Access-Control-Allow-Origin头,与传入的Origin值匹配。如果设置缓存响应而不设置Vary,则具相同源的响应可能用于具有不通源的请求,这将使CORS检查失败并完全阻塞请求

如果使用依赖于请求的其他 CORS 响应标头,你应该在此处包含它们,例如:

  Access-Control-Allow-Headers: my-custom-header
  Access-Control-Allow-Methods: GET, POST, PUT, DELETE
  Vary: Access-Control-Request-Headers, Access-Control-Request-Method

在Node.js中缓存CORS

如果你使用 Express 框架,那么你可能正在使用cors模块来处理 CORS

默认情况下,这根本不启用任何类型的缓存,但你可以Access-Control-Max-Age通过传递maxAge值进行配置。


  app.use(cors({
      maxAge: 86400,
      preflightContinue: true  
  }));

希望对你有帮助!!

评论:

    X

    备案号 皖ICP备19021899号-1  技术支持 © 947968273@qq.com