这次我是真的服了,蘑菇视频官网的离线播放问题我终于定位到原因了
这次我是真的服了,蘑菇视频官网的离线播放问题我终于定位到原因了

最近收到好几个用户的反馈:在蘑菇视频官网把视频“离线缓存”到 PWA 或页面缓存后,回到无网络环境,视频要么完全无法播放,要么只能播放开头几秒,无法快进、断点续播。作为做产品与前端多年的人,这种问题听着像是缓存策略或断点请求(Range)被搞乱了;深入排查之后,果然不是浏览器的锅,而是我们服务端 + Service Worker + CDN 配置三方配合失误造成的“连环坑”。把整个定位和解决过程整理成这篇文章,方便遇到同样问题的人少走弯路——顺便也展示一下我解决这类问题的流程和能力。
症状复现(我如何确认问题存在)
- 在桌面 Chrome、移动 Chrome 的 PWA 模式里,正常联网时视频播放完全正常。
- 离线后打开已缓存页面:视频卡在载入,控制条显示可播放时长异常,尝试快进或跳跃时无响应,控制台无明显的 JS 报错,但网络面板显示有请求被拦截或返回不完整。
- 使用 curl 带 Range 请求(curl -H "Range: bytes=0-1023" -I …)直接访问媒体文件时,部分服务器返回 200 OK 而非 206 Partial Content,或根本不支持 Accept-Ranges。
定位步骤(按我实际做过的顺序)
- 复现并记录环境:确认为 PWA 离线/浏览器缓存场景,而非特定设备。
- 抓包比对:联网正常播放时的请求与离线尝试时的请求差异(尤其看请求头里的 Range,以及响应头里的 Accept-Ranges、Content-Range、Cache-Control)。
- 检查 Service Worker:看 fetch handler 是否处理了带 Range 的请求,是否存在把所有请求返回缓存的泛化逻辑。
- 直连 origin 与 CDN:绕过 CDN 或直接到 origin 测试 Range 响应,确认是 origin、CDN 还是两者之间的问题。
- 排查 nginx/CDN 配置:查看是否有规则导致 206 被转为 200、或删除了 Content-Range/Accept-Ranges,或把视频作为普通文件强制 gzip 压缩/改变响应流式传输方式。
真正的根因(结论) 问题是多因叠加导致的,但核心是:我们在静态资源交付链上破坏了“字节分段(byte-range)支持”的能力。具体表现为两点:
- Service Worker 的 fetch 逻辑没有正确处理带有 Range 请求的情况,简单地用缓存的完整响应去回复了带 Range 的请求,从而导致浏览器无法得到 Partial Content(206),播放器无法正常 seek/续播。
- CDN/边缘缓存在某些配置下移除了 Accept-Ranges/Content-Range,或把对 Range 请求的响应转化为 200,导致即便 origin 支持 Range,终端也拿不到正确的分段响应。
我做的修复(可直接采纳的改法)
- Service Worker 层面:
- 对于可能会被浏览器以 Range 请求访问的媒体资源,fetch handler 需判断请求是否含有 Range 头。如果含有,应当将请求直接转发到网络(fetch(event.request))并让网络返回 206;或者,如果要从缓存提供响应,必须按照 Range 头返回对应的 206 分段响应(这通常比较复杂,不推荐缓存完整大文件再做分段响应)。
- 所以我的做法是:不把大视频文件作为普通缓存项预缓存到 SW Cache;允许 SW 对这些请求做 network-first 或直接 passthrough,使浏览器能与支持 Range 的服务器直接交互。
- CDN / 服务器层面:
- 确认 origin 支持 Range:服务器要能返回 206 Partial Content 并带上 Content-Range 与 Accept-Ranges: bytes。
- 配置 CDN 保留这些头部,不要在边缘去掉它们;确保 CDN 能向客户端转发 206(部分 CDN 需要显式打开“支持字节范围请求/byte-range”的选项)。
- 避免对视频资源进行不必要的 gzip 或代理变换,保证流式传输一致性。
- 体验性改进(长期方案):
- 对于需要离线观看的内容,考虑采用分段方案(HLS/DASH),把小的片段缓存到 IndexedDB 或 Cache Storage,更好地兼容断点播放与带宽限制。
- 对于 PWA 场景,分离“页面资源”的缓存策略和“媒体资源”的缓存策略。页面静态资源可 aggressive cache,媒体文件采用 network-first 或分段缓存。
验证方法(我如何确认修好了)
- 用 curl 发带 Range 的请求到 CDN edge 和 origin,确认两端都返回 206 且头部完整(Accept-Ranges、Content-Range)。
- 在浏览器网络面板里观察离线模式下的视频请求,确认播放期间没有被 SW 拦截返回错误的 200 替代品。
- 真机离线测试:先在在线时进入页面、启动播放并等待缓存逻辑触发,再切换到离线,测试播放 / 快进 / 断点续播行为是否正常。
给开发和产品的几点建议(可落地)
- 把“是否支持 Range 请求”纳入发布检查项,尤其是大型媒体上线流程。
- 对 CDN 的缓存规则做白名单,媒体文件要保留必要的头部;把 Service Worker 的行为写入文档并加入回归测试。
- 如果产品对离线播放有刚性需求,优先考虑 HLS/DASH + 小片段策略,而不是把整段 mp4 放在 SW 里缓存。
我做了蘑菇影视在线观看的界面布局对比:平板差异比我想象的大
« 上一篇
2026-05-02
用蘑菇视频下载前先做这件事:画中画体验能好一大截
下一篇 »
2026-05-03