FumadocsZDecode
网络 & HTTP

HTTP 缓存

一、为什么需要缓存

每次请求都去服务器拿资源,慢且浪费带宽。缓存的本质是把拿过的资源存在本地,下次直接用或快速验证


二、两种缓存机制

强缓存 — 不发请求

浏览器检查响应头,缓存未过期则直接用本地资源,不与服务器通信。

相关响应头

# 旧方案(HTTP/1.0)
Expires: Thu, 20 May 2027 12:00:00 GMT    # 绝对时间,有时区问题

# 新方案(HTTP/1.1,优先级更高)
Cache-Control: max-age=31536000           # 相对时间,单位秒(1 年)

命中时 DevTools 显示 200 (from memory cache)200 (from disk cache)无网络请求

常见策略

# 带 hash 的 JS/CSS → 强缓存一年
Cache-Control: max-age=31536000

# HTML 入口文件 → 不强缓存(保证能拿到最新资源引用)
Cache-Control: no-cache

协商缓存 — 问一下服务器

强缓存过期后(或设了 no-cache),浏览器带着标识去问服务器资源有没有变。

两套方案

# 方案一:基于修改时间(HTTP/1.0)
首次响应:Last-Modified: Wed, 20 May 2026 10:00:00 GMT
再次请求:If-Modified-Since: Wed, 20 May 2026 10:00:00 GMT

# 方案二:基于内容指纹(HTTP/1.1,优先级更高)
首次响应:ETag: "abc123"
再次请求:If-None-Match: "abc123"

服务器判断结果

  • 没变 → 304 Not Modified,body 为空,浏览器用本地缓存
  • 变了 → 200,返回新资源

三、304 是什么

浏览器:这个资源我有一份,指纹是 "abc123",变了吗?
服务器:没变。

       304 Not Modified(不传 body,省带宽)

       浏览器使用本地缓存的资源

虽然比强缓存多一次网络往返,但不传资源 body,对大文件(图片、JS 包)节省明显。


四、完整流程

浏览器请求资源

    ├─ Cache-Control / Expires 未过期?
    │     ├─ 是 → 200 (from cache)        强缓存命中,不发请求
    │     └─ 否 ↓

    ├─ 携带 If-None-Match / If-Modified-Since 发请求
    │     ├─ 资源未变 → 304               协商缓存命中,用本地缓存
    │     └─ 资源已变 → 200 + 新资源

五、ETag 比 Last-Modified 好在哪

Last-ModifiedETag
精度秒级,1 秒内多次修改检测不到内容指纹,改一个字节都能检测
误判场景内容没变但 mtime 变了(如重新部署)会误判过期只看内容,不误判
服务器开销需计算 hash,略大

六、口诀

强缓存不问,协商缓存问一下。强缓存看 Cache-Control,协商缓存看 ETag + 304

On this page