HelloWorld 浏览器缓存教程

浏览器缓存是提升网页加载速度的关键;本教程从原理、分类、HTTP 头、Service Worker、调试与实战配置等方面逐步讲解,教你在开发与运维中合理设置缓存策略,权衡性能与一致性,避免常见陷阱,并给出典型示例与排查流程,方便在静态资源、API 与 SPA 等场景中作出最佳决策。兼顾移动端与安全性。

HelloWorld 浏览器缓存教程

HelloWorld 浏览器缓存教程

为什么要关心浏览器缓存(用最简单的话说)

想象一下,你的网页像一本书,第一次打开要从书店买回来(下载全部资源),第二次如果书在家里(缓存),就立刻能读。浏览器缓存就是把“书”留在用户那儿,让后续访问更快、带宽更省、服务器压力更低。但也有副作用:如果书变了,用户可能拿到的是旧版。

核心概念:缓存的几种类型和关键因素

浏览器端常见缓存类型

  • 强缓存(Freshness):浏览器直接使用本地缓存,不向服务器验证。依靠 Cache-ControlExpires
  • 协商缓存(Validation):浏览器先询问服务器资源是否更新,使用 If-Modified-Since / If-None-Match,服务器返回 304 或新内容。
  • 内存缓存磁盘缓存:内存快但短暂,磁盘持久但读取稍慢,浏览器根据资源大小、类型决定存放位置。
  • Service Worker 缓存:由开发者通过脚本控制,适合离线或精细化缓存策略。

重要 HTTP 头及其语义

  • Cache-Control: 当前主流且优先级高,常见指令有 max-age, no-cache, no-store, must-revalidate, public, private
  • Expires: 旧方案,指定绝对过期时间,HTTP/1.1 推荐 Cache-Control 优先。
  • ETag: 资源指纹,协商缓存时服务器通过对比 ETag 决定是否返回 304。
  • Last-Modified: 资源的最后修改时间,作为较粗糙的协商缓存依据。

如何选择缓存策略(按资源类型)

不同资源应采用不同策略,这里给出常见分类和推荐做法,便于快速决策。

静态资源(图片、字体、JS、CSS)

  • 大多数可设置长期缓存,例如 Cache-Control: public, max-age=31536000, immutable,并使用版本号/哈希(如 file.abc123.js)来实现更新时立即生效。
  • 如果无法使用文件名哈希,可采用短期缓存并配合强制刷新机制。

API 响应(动态数据)

  • 通常需短期缓存或不缓存:Cache-Control: private, max-age=0, must-revalidate 或直接 no-cache(允许协商缓存)。
  • 对于可缓存的公共 API,请考虑 ETag 或短 max-age,并结合服务端处理 304 减少带宽。

单页应用(SPA)

  • HTML 主文档应设置短缓存(甚至不缓存),以避免用户长期加载旧版应用。静态资源(bundle、chunk)用长缓存并带哈希。
  • Service Worker 可做更复杂的离线策略:prefetch 静态资源、network-first 或 stale-while-revalidate 等。

具体 HTTP 头实例(直观表格)

场景 示例头 说明
长期缓存(静态资源) Cache-Control: public, max-age=31536000, immutable 资源一年内不改变,浏览器直接使用本地缓存
短期缓存(API) Cache-Control: private, max-age=60 适用于频繁更新但短时间可缓存的数据
强制验证 Cache-Control: no-cache 每次都向服务器验证,适合敏感或频繁变动的内容
完全不缓存 Cache-Control: no-store 不在任何地方存储,适合银行、隐私数据

服务器配置示例(实战)

Nginx:静态文件长缓存

在 nginx 配置中把静态目录的响应头设好就行,示例配置(请根据实际环境放到合适的 location):

location /static/ { expires 365d; add_header Cache-Control “public, max-age=31536000, immutable”; }

Nginx:API 设置协商缓存

对于 API,建议返回 ETag 并合理设置缓存头:

add_header Cache-Control “private, max-age=60, must-revalidate”;

Apache(.htaccess)示例

常见的静态缓存设置:

ExpiresActive On
ExpiresByType image/png “access plus 1 year”
Header set Cache-Control “public, max-age=31536000, immutable”

Service Worker:更细颗粒度的控制

Service Worker 可以拦截请求并决定用缓存、网络还是两者结合。常见策略:

  • Cache First:先查缓存,若没有再请求网络。适合图片、字体。
  • Network First:先请求网络,失败再用缓存。适合 API 或动态内容。
  • Stale-While-Revalidate:返回缓存同时后台拉取更新并替换缓存,用户体验好且兼顾更新。

简单示例(伪代码思路):在 fetch 事件里尝试 caches.match(request),若存在就返回,同时在后台 fetch 最新并用 caches.put 更新。嗯,就是这么直白。

调试与排查流程(Chrome 为例)

  1. 打开 DevTools(F12),切换到 Network 面板,勾选 Disable cache(注意:只有打开 DevTools 时有效)。
  2. 查看请求的 Response Headers:检查 Cache-Control、Expires、ETag、Last-Modified。
  3. 观察 Status:200 表示返回新内容,304 表示协商缓存命中但服务器未返回新内容。
  4. 利用 Application 面板查看 Cache Storage(Service Worker)、Storage 下的浏览器缓存。
  5. 如果不生效,注意中间代理(CDN、反向代理)可能会覆盖头,需要在这些层面也配置。

常见问题与应对(真接地气的那种)

1. 更新后用户仍看到旧资源

原因:使用长期缓存但未改变资源名。解决:引入文件名哈希(content hash),或在 HTML 中引用版本号查询字符串(不推荐长期用 querystring 管理静态文件)。

2. ETag 导致每次都验证但仍返回 200

可能是服务端没有正确生成 ETag 或计算逻辑每次都改变(比如包含时间戳)。检查生成方式,确保只有内容改变时 ETag 才变。

3. CDN 缓存与浏览器缓存冲突

CDN 在源站与用户之间,可能会缓存并返回与源站不同的头。排查时直接请求源站(绕过 CDN)或查询 CDN 控制台缓存策略,调整 Cache-Control 或设置 Cache-Key

性能与一致性的权衡(别只看速度)

缓存能提升速度,但过度缓存会降低内容一致性,有时可能影响功能(比如用户权限变更后看到旧页面)。因此:

  • 对关键页面(登录态、个人中心)使用 no-storeprivate
  • 对静态资源使用长期缓存 + 哈希,确保可缓存性与可控更新。
  • 对 API 使用短时缓存或协商缓存,结合 ETag/Last-Modified 降低带宽。

实战小贴士(我平时会这么做)

  • 构建流程中加入静态资源哈希(webpack、rollup 等支持),部署后可放心将这些文件设置为长期缓存。
  • HTML 主文件设置短缓存甚至不缓存,CDN 层用 stale-while-revalidate 策略可以在保证可用性的同时平滑更新。
  • 在开发阶段频繁遇到缓存问题,先在浏览器中勾选“Disable cache”,确认问题不是缓存引起的。
  • 在后端统一输出缓存头,避免在不同服务或微服务之间出现不一致。

快速排查清单(可复制到你的笔记里)

  • 检查响应头:Cache-Control、Expires、ETag、Last-Modified。
  • 是否使用文件名/哈希?若没有,考虑增加。
  • CDN/代理是否覆盖了头?尝试直接请求源站。
  • Service Worker 是否拦截并返回旧缓存?考虑 unregister 并重试。
  • 调试浏览器 DevTools 的 Network 与 Application 面板。

一些典型配置示例(便于复制粘贴)

用途 示例头
静态资源长期缓存 Cache-Control: public, max-age=31536000, immutable
HTML 主文档 Cache-Control: no-cache, must-revalidate
敏感数据 Cache-Control: no-store

最后说两句(随手记录的体会)

缓存听起来复杂,但本质是“什么时候可以让用户用旧东西,什么时候必须给他最新东西”。把资源分级、用哈希、合理设置头,加上 DevTools 调试,大多数问题就能迎刃而解。嗯,平常我会先把静态资源哈希做好,再看 HTML 的缓存策略;遇到缓存问题,先怀疑 Service Worker 和 CDN。就这样,慢慢调准,你的网站会既快又靠谱。