HTTP缓存头对fetch请求生效,但需显式配置cache选项:default遵循响应头、force-cache强制用缓存、no-cache强制验证;默认不缓存。

HTTP 缓存头对 fetch 请求是否生效
生效,但只影响底层网络层——fetch 发起的请求会走浏览器缓存策略,前提是服务端返回了正确的 Cache-Control 或 Expires 响应头。但注意:fetch 默认不会读取缓存(除非显式配置),和 <img alt="HTML缓存机制怎么处理异步加载组件" > 或 <script></script> 这类资源行为不同。
常见错误是以为加了 Cache-Control: max-age=3600 就自动缓存 fetch 结果。实际上必须手动告诉 fetch 使用缓存:
-
fetch(url, { cache: 'default' }):遵循 HTTP 头(推荐) -
fetch(url, { cache: 'force-cache' }):跳过验证,强制用缓存(即使过期) -
fetch(url, { cache: 'no-cache' }):强制验证(发带If-None-Match的请求) - 漏写
cache选项 = 等价于'default',但若响应头没设缓存策略,就完全不缓存
localStorage 存 HTML 片段时怎么避免脏数据
直接把 fetch 返回的 HTML 字符串塞进 localStorage 很危险:服务端更新了模板,但本地还用着旧 HTML,用户看不到变更。更糟的是,如果多个异步组件并发写同一个 key,后写的会覆盖前写的。
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
- 存的时候必须附带版本标识,比如
localStorage.setItem('nav-html-v2', html),而不是'nav-html' - 读的时候先检查是否存在对应版本 key,不存在再触发
fetch,成功后再写入新版本 - 别用
JSON.stringify(html)包一层再存——HTML 字符串本身不含控制字符,直接localStorage.setItem(key, html)即可 - 如果服务端支持 ETag,fetch 响应里有
ETag头,可以把它和 HTML 一起存在 localStorage,下次请求带上If-None-Match,由服务端决定是否返回 304
Service Worker 拦截异步 HTML 加载的坑
想用 Service Worker 缓存 HTML 片段(如 /components/header.html),得特别注意匹配逻辑和响应构造。很多失败是因为 SW 返回了空响应或类型错乱。
立即学习“前端免费学习笔记(深入)”;
- 注册后必须刷新页面才能生效,首次加载永远走网络(SW 不拦截当前页激活前的请求)
- 拦截
fetch事件时,不能只靠event.request.url.includes('/components/'),要严格匹配event.request.destination === 'document'或'text',否则可能误劫持 JSON 请求 - 用
cache.match()查缓存时,记得传{ ignoreSearch: true },否则带时间戳参数的请求(如?t=123)永远不命中 - 从 cache 读出的 Response 是流式体,不能直接
response.text()后再 new Response()——会报 “body used” 错误;要用response.clone()
SSR 场景下 HTML 异步组件的缓存一致性
服务端渲染时,组件 HTML 已经内联在首屏中;客户端 hydrate 后又去 fetch 同一地址,结果可能不一致——比如服务端用了旧模板,客户端 fetch 到新 HTML,插入后 DOM 结构错乱,hydration 报 mismatch。
- 服务端输出的 HTML 片段必须和服务端接口返回的内容**完全一致**,包括空格、换行、属性顺序
- 最稳做法:服务端渲染时,把组件内容 hash 进一个全局变量(如
window.__COMPONENT_HASH__ = { 'header': 'a1b2c3' }),客户端 fetch 前先比对 hash,不一致就跳过缓存直接请求 - 不要依赖
localStorage或 SW 缓存来“修复” SSR 不一致——这是掩盖问题,不是解决问题 - 如果组件内容动态依赖用户状态(如登录名),服务端和客户端必须用同一套数据源,且缓存 key 要包含用户身份标识(如
header-user-123)


















