博客歪歪博主素颜照

200 OK (from cache) 与 304 Not Modified

为什么有的缓存是 200 OK (from cache),有的缓存是 304 Not Modified 呢?很简单,看运维是否移除了 Entity Tag。移除了,就总是 200 OK (from cache)。没有移除,就两者交替出现。

最近在做百度云观测的 nginx 配置优化。从知乎上看到这个问题:“阿里云存储如何让浏览器始终以200 (from cache)缓存图片?”,提问者强调 200 OK (from cache) 和 304 Not Modified 的区别,有感而发。

其实, 200 OK (from cache)  是浏览器没有跟服务器确认,直接用了浏览器缓存;而 304 Not Modified 是浏览器和服务器多确认了一次缓存有效性,再用的缓存。

它们都是在设置了缓存的情况下触发的。

那么,两者触发的时机有什么区别呢?200 OK (from cache) 是直接点击链接访问,输入网址按回车访问也能触发;而 304 Not Modified 是刷新页面时触发,或是设置了长缓存、但 Entity Tags 没有移除时触发。这是经过查阅资料得出的结论。博主实际测试了一下,结论与之相符:

直接访问有缓存的网站都触发 200 OK (from cache)
图1 – 直接访问有缓存的网站都触发 200 OK (from cache)
刷新浏览器会触发 304 Not Modified
图2 – 刷新浏览器则会触发 304 Not Modified
同一域名下,没有 Entity Tag 的资源直接访问,是 200 OK (from cache) 的结果
图3 – 同一域名下,没有 Entity Tag 的资源直接访问,是 200 OK (from cache) 的结果
同一域名下,有 Entity Tag ,直接访问就会触发 304 Not Modified
图4 – 同一域名下,有 Entity Tag ,直接访问就会触发 304 Not Modified

现在一般都会设置长时间的缓存,正确设置方式参考这两篇笔记:

参考文献

后记

搜索了一下,发现这个问题,在网络上并还没有定论,也没发现有人去实测。

想想也对,现在网络那么快,304 Not Modified 还是 200 OK (from cache),如果不是较真地追求速度,可能大家都觉得区别不大,从而也就没发现这个问题了。

博主截图的域名是某著名 IT 公司的 CDN(已反馈)。可见犯这个错误的运维 GG 还真不少呢!

本文并不是说影响浏览器缓存只有 ETag 这一个因素的意思,请大家不要误解。只是就“为什么我加了缓存,有的却是 304 Not Modified, 而不是 200 OK(from cache)”这件事给出一个一针见血的原因和解答。本文也发在了 div.io 上,详细的 ETag 补充知识可以看 @hefangshi 补充的评论

发布者

袁 源

我是袁源,职业是前端开发 关注我的新浪微博

14 thoughts on “200 OK (from cache) 与 304 Not Modified”

  1. 好像楼主描述的并不是完全适用 今天看见一个页面的js文件,
    https://developer.mozilla.org/en-US/docs/Web/HTTP 用chrome打开, network分析editor-js.js这个文件, 发现:
    1. 强制刷新(Ctrl+F5), 即, 第一次访问, 返回200 ok, 没有问题

    第一次普通刷新(或者直接在url地址栏回车), 效果都是返回 304 Modified
    接下来无论进行多少次 普通刷新(或者直接在url地址栏回车), 返回都是 200 ok (from disk cache)

    这不诡异么? 感觉第二步就应该和第三步一样
    而且发现 浏览器的刷新 和 回车怎么在第一步之后, 效果都是一样的? 太诡异了, 印象中是不一样的才对!

  2. 好像楼主描述的并不是完全适用 今天看见一个页面的js文件,
    https://developer.mozilla.org/en-US/docs/Web/HTTP 用chrome打开, network分析editor-js.js这个文件, 发现:
    1. 强制刷新(Ctrl+F5), 即, 第一次访问, 返回200 ok, 没有问题

    第一次普通刷新(或者直接在url地址栏回车), 效果都是返回 304 Modified
    接下来无论进行多少次 普通刷新(或者直接在url地址栏回车), 返回都是 200 ok (from disk cache)

    这不诡异么? 感觉第二步就应该和第三步一样

  3. 目前有个需求,就是“新窗口打开”显示304,我想了各种方法都是无法实现,如果设置cache-control:public就是200(from cache),如果设置cache-control:no-cache就是200,博主有方法吗?

    1. 嗯,刷新页面是用户想要获取新内容,所以让它真正的刷新了。而所有未曾改变的资源文件也只是从 200 from cache 变成 304 Not Modified 而已,也是很合理的

  4. 用Expires能达到最极限的缓存,毫无疑问这是最强的缓存方式,304还需要RTT。但Expires在更新清缓存的时候必须改URL,要解决个自动化的问题。流量大的网站,要解决先上页面还是先上静态文件的问题,不然上线过程中访问的用户总会存在缓存错误的问题,不管是旧页面新静态文件,还是新页面旧静态文件。最完美的办法是文件名整个换新,先上静态文件,云龙那边应该有这种方式的解决方案。

    1. 文章说的就是,去掉 Entity Tag 就没有 304 的过程啦~文件名的问题,由于我们有长缓存加上 MD5 版本号的机制,实际上是代替了 Entity Tag,所以你说的这个问题已经解决啦~ 当然,自动合并加上自动更名是更好的解决方案,计划这两周就会上这个新方案了。

    2. 其实我觉得 Entity Tag 本身就是一个很好的版本管理机制。可惜我知道的太少,不知道怎么让它在多服务器中都保持一致。否则版本号也可以免了。

        1. 其实和压缩后的 gzip 无关,应该是按压缩前的来算的。这里主要可能存在的问题是,大公司会有多台服务器做负载均衡,而每台服务器对同一个文件计算出的 entity tag 有可能完全不同,这就会导致同一个文件在每台服务器都需要下载一次。所以干脆禁用之。如果每台服务器对同一个文件计算出的 entity tag 完全一样,那么就完全不用禁用。

发表评论

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