用<object>加载HTML时,其内嵌资源离线不显示,根本原因是子文档资源请求需单独匹配缓存路径,且必须全部使用根绝对路径并显式缓存。

直接说结论:用 <object> 加载 HTML 文件时,其内嵌资源(比如 <img src="...">)不会自动继承父页面的 Service Worker 缓存逻辑——哪怕父页和 object 内容同源,也得单独匹配请求 URL 并显式缓存。
为什么 <object data="/page.html"> 里的图片不显示(离线时)
根本原因不是 <object> 本身被限制,而是浏览器对它发起的子资源请求(如图片、CSS、JS)走的是独立 fetch 流程,而你的 Service Worker 的 caches.match() 没有覆盖这些路径。
- 常见错误现象:在线时一切正常;切到离线后,
<object>加载出空白或报net::ERR_FAILED,DevTools 的 Network 面板里能看到/img.png请求状态为(failed) - 关键点:Service Worker 只会拦截当前页面上下文发起的请求。但
<object data="...">加载的 HTML 是一个“嵌入式文档”,它内部的资源请求是该子文档上下文发出的,URL 必须和你缓存数组中声明的路径字面完全一致 - 典型坑:你缓存了
"/img.png",但子 HTML 里写的是"img.png"(相对路径),导致匹配失败
object 加载的 HTML 必须用绝对路径引用资源
子 HTML 文件中的所有资源链接必须使用根绝对路径(/xxx),否则缓存键无法对齐。
- ✅ 正确示例(子 HTML 中):
<img src="/assets/logo.png" alt="">,同时确保ASSETS_TO_CACHE包含"/assets/logo.png" - ❌ 错误示例:
<img src="logo.png">或<img src="../images/logo.png">—— 这些路径在缓存匹配时会被解析为不同 key,caches.match()找不到对应 entry - 额外注意:
<object>的data属性值本身也要是绝对路径,比如data="/pages/embed.html",不能是data="pages/embed.html"
Service Worker 的 fetch 事件必须处理子文档资源请求
你原来的 fetch 逻辑可能只处理了主页面导航请求,但没覆盖子文档加载的资源类型(比如 request.destination === 'image' 或 'document')。
立即学习“前端免费学习笔记(深入)”;
- 检查
event.request.destination:object 加载 HTML 时,其request.destination是"document";加载图片时是"image"。不要用response.type !== 'basic'过滤掉它们 - 简化匹配逻辑:去掉对
response.type的判断,直接caches.match(event.request)—— 只要 URL 匹配且缓存存在,就返回 - 务必加 fallback:如果缓存未命中,且处于离线状态,应返回一个兜底响应(比如空 HTML 或 404 页面),而不是让请求静默失败
验证缓存是否真包含所有子资源
别只看主页面资源是否在 Cache Storage 里,要手动确认子 HTML 引用的每个 <img>、<link>、<script> 路径都已缓存。
- 打开 Chrome DevTools → Application → Cache Storage → 点开你的缓存名 → 展开所有 entries
- 逐个核对:子 HTML 中的
src="/a/b/c.jpg"是否出现在列表里?注意大小写、斜杠、查询参数(?v=1算不同 key) - 如果缺失,检查
install事件里cache.addAll()的数组是否漏掉了该路径,或者在线时该资源返回了 404/500 导致缓存失败
最常被忽略的一点:子 HTML 文件自己也必须被缓存,且它的 Content-Type 必须是 text/html。如果服务器返回了 application/octet-stream 或其他类型,浏览器可能拒绝执行其中的脚本或加载内嵌资源,即使缓存成功了也白搭。



















