Skip to content

HTTP Cache-Control 与 ETag ​

先从一个浏览器可观察问题开始:同一操作为什么会改变节点、事件、请求、存储或辅助技术状态?本节把“HTTP Cache-Control 与 ETag”拆成输入、所有者、中间状态和输出,避免只背 API。

最小实验 ​

下面的脚本不依赖外部站点。把它保存为 cache-http.mjs,用 Node 22 运行;第二次请求会命中同一个内存缓存,改动 etag 后才会重新取值。

js
const server = new Map([['/profile', { etag: 'v1', body: { name: 'Ada' } }]])
const cache = new Map()
async function request(path) {
  const previous = cache.get(path)
  const resource = server.get(path)
  if (previous?.etag === resource.etag) return { source: 'cache', ...previous }
  const next = { etag: resource.etag, body: structuredClone(resource.body) }
  cache.set(path, next)
  return { source: 'network', ...next }
}
console.log(await request('/profile')) // network, v1
console.log(await request('/profile')) // cache, v1
server.set('/profile', { etag: 'v2', body: { name: 'Grace' } })
console.log(await request('/profile')) // network, v2

运行后应看到 network → cache → network。这里的 etag 只是实验中的缓存验证器;真实 HTTP 中由服务端通过 ETag 和条件请求决定 304,浏览器的 HTTP 缓存也不等同于 Cache API。

运行前记录环境和输入序列;运行后记录回调顺序、对象身份、可见文本、网络/存储变化或可访问名称。再改变一个条件:取消、卸载、重复触发、权限拒绝、跨源、键盘路径或不支持该 API 的浏览器。

规则与边界 ​

  • 平台保证、浏览器实现和业务约定必须分开;一个浏览器中的结果不能自动推广到所有宿主。
  • 每个监听器、请求、观察器、缓存和焦点操作都要有清理/取消责任;页面或组件离开后不能继续写状态。
  • 用户输入、URL、HTML、消息和持久化数据按不同信任边界处理;类型正确不代表内容可信。
  • 失败、取消、超时、权限拒绝、配额不足和不支持要有不同的可观察结果。

练习 ​

  1. 写出成功、失败、取消/卸载和降级四条路径的断言。
  2. 改变一个时序,解释哪条因果边发生变化。
  3. 说明一个替代 API 何时更适合及其代价。

查看本节答案

下一步 ​

完成答案核对后继续本章下一篇,并把实验日志保存在自己的项目中。

用心记录每一步成长