浏览器两次请求同一张图片:强缓存、协商缓存是怎么接力的

举报
yd_246930210 发表于 2026/11/11 15:58:11 2026/11/11
【摘要】 1. 同一张图片,第二次请求到底发不发?浏览器第一次请求 banner.jpg,服务器返回 200 和图片内容。第二次再请求同一张图,有三种可能:不发请求,直接读本地缓存;发请求,服务器说“没变过,用你手里那份”,返回 304,不传图片;发请求,服务器说“变了”,返回 200 和新图片。哪种发生,取决于两道关卡:先过强缓存,再过协商缓存。两道关卡用的响应头不一样,分工也不一样。 2. 第一...

1. 同一张图片,第二次请求到底发不发?

浏览器第一次请求 banner.jpg,服务器返回 200 和图片内容。第二次再请求同一张图,有三种可能:

  • 不发请求,直接读本地缓存;
  • 发请求,服务器说“没变过,用你手里那份”,返回 304,不传图片;
  • 发请求,服务器说“变了”,返回 200 和新图片。

哪种发生,取决于两道关卡:先过强缓存,再过协商缓存。两道关卡用的响应头不一样,分工也不一样。

2. 第一道关卡:强缓存,过期前不发请求

第一次请求的响应头里有:

HTTP/1.0 200 OK
Cache-Control: max-age=60
ETag: "3a429cdec9174cd1c3bfd032517076c1"
Last-Modified: Wed, 11 Nov 2026 03:30:00 GMT

Cache-Control: max-age=60 的意思是:这份响应在 60 秒内是新鲜的。60 秒内浏览器再请求同一张图,根本不发请求,直接读缓存,状态显示 200 from cache。服务器完全不知道这次请求发生过。

强缓存只认时间,不认内容。60 秒内服务器上的图片就算换了,浏览器也不会知道——这是强缓存的代价,换来的是零请求、零流量。

3. 第二道关卡:协商缓存,过期后问一句“变了没”

60 秒过去,强缓存过期。浏览器这次要发请求,但先在请求头里带上上次记下的标识,问服务器图片变了没有:

curl -i -H 'If-None-Match: "3a429cdec9174cd1c3bfd032517076c1"' http://127.0.0.1:8899/banner.jpg

服务器拿请求里的 If-None-Match 和当前文件的 ETag 一比对,没变:

HTTP/1.0 304 Not Modified
ETag: "3a429cdec9174cd1c3bfd032517076c1"

304 没有响应体,浏览器复用本地缓存。省了图片传输,只花了一次往返问一句。

如果图片更新了,ETag 对不上,服务器返回 200 和新图片:

curl -i -H 'If-None-Match: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' http://127.0.0.1:8899/banner.jpg
HTTP/1.0 200 OK
Cache-Control: max-age=60
ETag: "3a429cdec9174cd1c3bfd032517076c1"
Last-Modified: Wed, 11 Nov 2026 03:30:00 GMT

浏览器拿到新图片,同时记下新的 ETag 和新的 max-age=60,下一轮从强缓存重新开始。

4. ETag 和 Last-Modified:谁优先,谁兜底

协商缓存有两个标识,优先级不同:

  • ETag / If-None-Match 优先。ETag 是文件内容的哈希摘要,内容变了它一定变,内容没变它一定不变,判断最准。上面三次请求走的就是这条路。
  • Last-Modified / If-Modified-Since 兜底。没有 ETag 时,浏览器用上次的 Last-Modified 时间问服务器“这个时间之后改过吗”。它的精度只有秒,1 秒内改两次是认不出来的;而且文件被重新保存、内容没变,修改时间变了也会误判为“变了”。

所以有 ETag 就用 ETag,Last-Modified 只当后备。两个标识同时存在时,浏览器先发 If-None-Match。

5. 完整流程:banner.jpg 的三次请求

把上面的实测串起来,max-age=60 的一张图,浏览器是这样走的:

  1. 第一次请求:没有缓存,发请求,服务器返回 200、图片、Cache-Control: max-age=60、ETag、Last-Modified。浏览器存下图片和这三个头。
  2. 60 秒内第二次请求:强缓存未过期,不发请求,200 from cache。
  3. 60 秒后第三次请求:强缓存过期,发请求带 If-None-Match;图片没变,服务器返回 304,浏览器复用本地图片;图片变了,服务器返回 200 和新图片,浏览器更新缓存,下一轮重新计时。

强缓存决定“问不问”,协商缓存决定“传不传”。max-age 过期不等于重新下载——304 那次只问了一句,图片一个字节都没传。

6. 容易踩的三个坑

  • max-age 设得太长,图片更新了用户看不到。强缓存期内浏览器不发请求,服务器换了图也白搭。解法是给静态资源文件名加哈希,内容一变 URL 就变,旧缓存自然失效。
  • 只配了 Last-Modified,没配 ETag。1 秒内改两次文件、或者文件被原样重新保存,都会误判。内容型资源优先配 ETag。
  • 看到 304 以为是缓存失效。304 恰恰是缓存命中:服务器确认本地那份还能用。真正重新下载的是 200。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。