V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Albertcord
V2EX  ›  程序员

Http Cache-Control 缓存策略问题,什么情况下设置 no-cache 会使得资源请求返回 200 (disk cache)?

  •  
  •   Albertcord · 240 天前 · 1473 次点击
    这是一个创建于 240 天前的主题,其中的信息可能已经有所发展或是发生改变。

    表现出来是问题所述,我这里讲下复现(人工复现)路径:

    我将系统部署回老版本 1.1.0 ,然后同事访问系统(为 1.1.0 ),我再部署新版本 1.2.0 ,同事 F5 刷新页面,访问系统。前端架构是用的微前端(老版本用的 micro-app ,新版本用的 qiankun ),获取子应用当然是微前端沙箱的 fetch (但是我理解这里都是没有影响的)。

    重点来了:同事机器访问 1.1.0 后就相当于缓存住了,之后访问 1.2.0 ,子应用的资源是 fetch 200 ,disk-cache ,然后请求头只有 Referer, User-Agent ,响应头里有 Cache-Control no-cache Last-Modified, Etag ,也就是 1.1.0 版本的子应用 entry (老的 html )

    我本机无法复现,查看 nginx 日志,确实同事机器是只在访问 1.1.0 的时候打到日志,后面都是走的本机缓存,我无法理解的是为什么 no-cache 会表现出强缓存的现象?

    我现在解决是先改了 html 策略为 no-store (而且吊诡的是,nginx 配置加了之后除了 Cache-Control no-cache 这一行,还多了一行 no-store ,难以理解),然后子应用访问时加时间戳(主要解决问题是这个方式,其实标题问题没有解决)

    我现在猜测是第一次访问时,不知道哪里的中间代理(中间人)加了强缓存(但是响应头的 Last Modified Etag 又是哪里来的?),或者用的东方通有什么 bug ?(但配置文件跟 nginx 一样的)

    测试浏览器都是 Chrome ,本机是最新 110 版本的,复现同事版本分别是 122 (最新)、96

    想问问社区大佬原因或者排查思路?赐教

    17 条回复    2024-04-26 10:28:04 +08:00
    epiloguess
        1
    epiloguess  
       240 天前
    从客户端的角度上来说,如果服务端配置了 no-cache,对于客户端的非首次请求,headers 里应该有 if-none-match.
    如果没有的话,有两种可能
    1.服务端一开始没有配置 no-cache,客户端缓存了内容,服务器此时配置 no-cache 是无效的,但客户端不应该收到 no-cache 的响应头
    2.客户端没有发送`if-none-match`的能力,导致虽然配置了 no-cache,但是只能用`last-modified`作为 fallback,这种情况虽然少见,但是确实可能存在

    OP 可能需要清空客户端的缓存,再做几组测试
    Albertcord
        2
    Albertcord  
    OP
       240 天前
    @epiloguess 第二种,如果使用 last-modified 作为 fallback ,也应该是 304 状态码
    我其实最难接受跟理解的就是这个 200 状态码然后走了 disk cache ,这个请求都不跟 nginx 服务作缓存的协商验证是否过期
    难受的是我本机复现不了,复现的了的同事没空配合我测试
    tool2dx
        3
    tool2dx  
       240 天前
    @Albertcord 200 是假的,是 disk cache 返回的,又不是服务器返回的。

    在 Expires 和 max-age 都没有过期的情况下,浏览器不会发送新的网络请求,哪怕是 304 也不会主动去获取。所以资源才需要加 hash 名字。
    epiloguess
        4
    epiloguess  
       240 天前
    @Albertcord `last-modified`也被用作浏览器的启发式缓存,不一定要返回 304 的,浏览器认为资源没过期直接从 disk cache 中返回了,状态码 200
    Albertcord
        5
    Albertcord  
    OP
       240 天前
    @epiloguess 这个有文档来源吗?颠覆了以往知识- -
    Albertcord
        6
    Albertcord  
    OP
       240 天前
    @tool2dx 可是我确认本机没有发 max-age or Expires
    epiloguess
        7
    epiloguess  
       240 天前   ❤️ 1
    @Albertcord Last-Modified is also used by crawlers to adjust crawl frequency, by browsers in heuristic caching, and by content management systems (CMS) to display the time the content was last modified.
    https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified

    也就是说,除了 If-Modified-Since 或 If-Unmodified-Since 会用到这个字段,其他地方也会用到这个字段
    JK9993
        8
    JK9993  
       240 天前
    @Albertcord #6 没有设置的话浏览器会给一个默认的值
    Albertcord
        9
    Albertcord  
    OP
       240 天前
    @epiloguess 看起来确实是这个原因,那就是 nginx 配置的 no-cache 其实没有挂上去,又有默认的 Last-Modified ,导致了启发式缓存
    Albertcord
        10
    Albertcord  
    OP
       240 天前
    @epiloguess 用 postman 获取是没有 Cache-Control 返回的,那就是这个 Last-Modified 导致了启发式的强缓存了
    就是不知道哪一层中间代理加的 Cache-Control no-cache ,中间有段时间没有返回吧,然后同事的浏览器在那个时刻访问了,触发了强缓存,而我的没有访问过
    我改下 ngxin 配置
    epiloguess
        11
    epiloguess  
       240 天前 via Android
    @Albertcord 大部分前端框架在 dev 阶段是返回 no cache 的,不过不清楚你目前是什么环境 建议用 curl 看后端返回的 headers
    Daath
        12
    Daath  
       240 天前
    如果仅仅只是想让浏览器 chrome 用到最新的页面版本的话,可以 F12 ,然后右键网页栏左侧的刷新按钮,就会出现三个`重新加载`的字样,然后通过这个强制刷新就应该可以访问到新版本页面
    Albertcord
        13
    Albertcord  
    OP
       240 天前
    @epiloguess 测试环境也有这个问题
    Albertcord
        14
    Albertcord  
    OP
       240 天前
    @Daath 解决环境问题,并不是本机开发用
    NeedI09in
        16
    NeedI09in  
       239 天前
    @NeedI09in 还有 211 之后的部分都在讲这里。
    NeedI09in
        17
    NeedI09in  
       239 天前
    HTTP/1.1 提供了几种限制对象缓存,或限制提供已缓存对象的方式,以维持对象的新鲜度。no-store 首部和 no-cache 首部可以防止缓存提供未经证实的已缓存对象:
    Pragma: no-cache
    Cache-Control: no-store
    Cache-Control: no-cache
    标识为 no-store 的响应会禁止缓存对响应进行复制。缓存通常会像非缓存代理服务器一样,向客户端转发一条 no-store 响应,然后删除对象。
    标识为 no-cache 的响应实际上是可以存储在本地缓存区中的。只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。这个首部使用 donot-serve-from-cache-without-revalidation 这个名字会更恰当一些。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2202 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 01:56 · PVG 09:56 · LAX 17:56 · JFK 20:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.