记一次将请求改为协商缓存的艰难过程

简单回顾一下前端缓存策略 ⛏️

  1. 强缓存:在请求头规定的max-age和expirse过期之前直接读取本地缓存的资源,如果已经过期则调用协商缓存
  2. 协商缓存:也叫弱缓存,以下都称为协商缓存。协商缓存是缓存过期,刷新缓存时间或者文件更新,返回新文件的缓存阶段。
    • 以下是协商缓存的过程:
    • 前端 首次 请求文件、静态资源时,请求响应头带上Etag/Last-Modified请求头
    • 告诉浏览器下一次同样的资源请求需要在请求头带上If-None-Match:值为上一个请求响应头的Etag,If-Modified-Since:值为上一个请求响应头的Last-Modified,服务器根据请求头的这两个字段匹配资源是否变更
    • 如果未变更,他们的值应该是一样的,返回304即可。如果变更了,值不一样,返回200和新的资源内容
    • 所以非首次请求资源才会带上If-None-Match/If-Modified-Since
    • 但是响应头每次都会带上Etag/Last-Modified(文件、静态资源会自动携带因为可能需要缓存,json字符串接口不会自动携带,普通接口不需要也不应该缓存)
  3. 新手请记住强缓存和协商缓存容易混淆的地方,强缓存和协商缓存不是非我即他的两种独立使用的策略。而是包含关系的缓存策略。强缓存开启一定包含协商缓存,因为强缓存资源到期需要使用协商缓存刷新强缓存的缓存时间
  4. 协商缓存的策略使用也是使用Cache-Control: max-ag=0(或者设置为no-cache)将强缓存时间设置为0强制开启协商缓存。强缓存和协商缓存可以理解为是前端缓存的不同阶段

需求背景 🔥

  1. 项目有一个全局请求配置文件的轮询接口,他会在发版时变更,轮询发现配置文件有变更则提示用户刷新页面,启用新版本。
  2. 但是有一天出BUG了,发版成功,但是客户端没有检测到版本变化。
  3. 打开Console控制台一看,原来接口被强缓存了,接口返回200(from disk cache),读取本地缓存文件肯定没有变化,检测不到发版更新。
    image.png

开始爬坑  ✏️

开始发现问题是开启了强缓存,心想这还不简单,直接改为弱缓存解决,easy。
还是太年轻了🤡🤡🤡
  1. 查阅MDN将Cache-Control设置为no-cache即可开启协商缓存
  2. 这里注意一下,no-cache不是不使用缓存,是每次都去服务器验证一下资源是否变更,变更则返回200和变更后的资源,未变更则返回304使用缓存。no-store才是不使用缓存。
    image.png

第一个坑:本地调试开启https没有合法证书缓存无效,本地改为http正常

  1. 查看请求,请求头加上了Cache-Control: no-cache,响应头也返回了Etag,但是没有返回304
    image.png

  2. 但接口没有被缓存,依然每次直接请求服务器(304才是协商缓存,它返回了200)
    image.png

  3. 第一个坑问题解决

     最后发现是本地当时开了https联调第三方https的接口,但是没有本地关联证书,裸奔https
     而浏览器不会缓存没有合法证书的https请求
     后面一次发到测试上发现缓存是有效的,线上是https有合法证书
     然后本地去掉https,缓存也有效了,🤮吐血,浪费了我好多时间
    

第二个坑:Cache-Control: no-cache缓存无效,需要改为Cache-Control: max-age=0

总所周知,程序解决了第一个坑,总会有第二个坑等着你
  1. 查看MDN、谷歌、百度看网友示例,设置为no-cache都可以开启协商缓存,但是我这里第二次请求没有带上弱缓存的请求头(If-None-Match/If-Modified-Since)

  2. 如下图所示(非首次请求截图),Cache-Control为no-cache,响应头带上了Etag/Last-Modified,但是请求头没有带上弱缓存的请求头,接口直接返回200而不是304没有使用协商缓存
    image.png

  3. 花了很多时间找不到答案,累了毁灭吧,又不是不能用,协商缓存可能也就快了一点点而已,折腾啥又不能涨工资,无所谓.jpg QAQ。
    5d99306c27bb1ee45a93e3359f5dc542.jpeg

  4. 在我快要放弃的时候,我看到了可以试一下将Cache-Control设置为max-age=0,果然了就可以了

     max-age表示在给定的时间内(单位秒)使用强缓存,直接读取本地缓存文件
     超过时间则请求服务器验证文件是否变更
    

    image.png

  5. 虽然对了,但为什么no-cache不行,我看MDN和别人的代码示例都说no-cache是可以,我认为实际上应该也是可以的,可能是中间网关做了什么处理?我也尝试过是否开启了Disable cache,但是我一直都是关的。百撕不得其姐,有没有懂哥赐教🫡(respect)!

问题来了,最开始的代码根本没有配置Cache-Control怎么默认开启了强缓存

  1. 又发现了一个奇怪现象,当我将Cache-Control请求头去掉,还原场景。获取该配置文件的接口刚开始还是304好好的,然后穿插了几个200强缓存(而且后面强缓存还变成连续的),然后又变成了304到底怎么回事?(该请求轮询时间是30s)
    image.png
  2. 最后在知乎找到了答案,明明没有配置任何缓存策略,浏览器还是给我强缓存了?
  3. 大概意思是没有配置任何缓存策略时会启用启发式缓存,则缓存时间cacheTime为响应头返回的(Date-lastModified)*0.1,所以就会一开始都是304因为cacheTime很小马上就过期了(不够30s),当cacheTime随着时间推移(资源未被更改)会越来越大,超过轮询的30s就变成了200强缓存。然后变成2个连续的200强缓存。当这个资源10天都未更改,那么这个请求一天都是强缓存,然后造成了项目发版了,但是没有发版提醒的BUG。
  4. 前端福尔摩斯(自封)🧐

结论 🏆

  1. 协商缓存无效可能是本地开启了https,改为http
  2. 设置Cache-Control: no-cache可能无效,使用Cache-Control: max-age=0
  3. 此次爬坑其实对业务来说无关痛痒,因为根本都没有遇到性能问题,这点性能提升对用户来说也是无感知的,但是此次爬坑让我对前端的强弱缓存有了更深的了解,之前我的理解前端的强弱缓存因为需要依赖后端返回的Etag、Last-Modified字段,所以应该需要后端或者负责Nginx配置的运维去负责管理的,原来前端也可以进行控制。也算是不枉费自己瞎折腾吧。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vgbire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值