蘑菇影视官网切到移动网络后的缓存管理,我给你一套可复制的操作

简介 当用户从 Wi‑Fi 切换到移动网络时,页面加载速度、流量消耗和用户体验都会受到影响。针对蘑菇影视这类内容以视频、图片为主的网站,合理的缓存策略和网络感知能力能显著降低移动网络流量、提升打开速度并减少失败播放。本篇文章给出一套可复制、可落地的前后端方案,包含检测网络变化、Service Worker 缓存策略、缓存清理/版本管理、资源降级与监测方法,帮助你在切换到移动网络后自动做出最合适的缓存与加载决策。
核心思路速览
- 在客户端实时感知网络类型(4g/3g/2g/slow-2g)并把信息传给 Service Worker 和页面脚本。
- 在移动网络下优先使用缓存(cache-first)并降级资源(低码率/小尺寸图片),必要时采用 network-first 以保证内容更新。
- 使用版本化缓存名与激活流程,确保平滑更新并能按需清理旧缓存。
- 配合服务器端 Cache-Control 与 ETag 减少不必要的流量。
- 监测存储配额与缓存命中率,定期回收或自动压缩缓存内容。
准备工作(先决条件)
- 网站已启用 HTTPS(Service Worker 要求)。
- 支持 Service Worker(现代浏览器)并可部署静态文件版本化。
- 后端可以按资源类型返回不同质量的文件(或通过参数/子域区分)。
操作步骤(可复制)
1) 在页面端检测网络状态并广播 使用 Network Information API(兼容性尚好)检测 effectiveType、downlink,并在变化时通知 Service Worker 或页面逻辑,决定是否切换策略。
示例代码(main.js):
function getNetworkInfo() {
const nav = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (!nav) return { effectiveType: 'unknown', downlink: null };
return { effectiveType: nav.effectiveType, downlink: nav.downlink };
}
function onConnectionChange() {
const info = getNetworkInfo();
// 通知 Service Worker
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({ type: 'NETWORK_CHANGE', info });
}
// 页面内部可以根据 info 做降级展示
window.dispatchEvent(new CustomEvent('network-change', { detail: info }));
}
if (navigator.connection) {
navigator.connection.addEventListener('change', onConnectionChange);
}
// 初始化广播一次
onConnectionChange();
关键点:
- effectiveType 可能是 '4g'、'3g'、'2g'、'slow-2g'、'unknown'。
- 可以结合 downlink(Mbps)做更精确的判断。
2) Service Worker 的缓存策略与动态切换 在 Service Worker 中实现多策略:对静态资源(CSS/JS/字体)使用 cache-first;对视频片段、封面图在移动网络下使用低质量版本或优先缓存;对 API/播放清单采用 network-first(当网络好时回落到缓存)。
示例 Service Worker(sw.js)精简版:
const CACHE_PREFIX = 'mogu-cache';
const CACHE_VERSION = 'v1';
const STATIC_CACHE = `${CACHE_PREFIX}-static-${CACHE_VERSION}`;
const DYNAMIC_CACHE = `${CACHE_PREFIX}-dynamic-${CACHE_VERSION}`;
let networkInfo = { effectiveType: '4g', downlink: 10 };
self.addEventListener('message', event => {
const data = event.data;
if (data && data.type === 'NETWORK_CHANGE') {
networkInfo = data.info || networkInfo;
}
});
self.addEventListener('install', event => {
event.waitUntil(
caches.open(STATIC_CACHE).then(cache => {
// 预缓存关键文件(注意移动网络下避免预缓存过多大资源)
return cache.addAll([
'/index.html',
'/css/app.min.css',
'/js/app.bundle.js',
'/images/logo-small.png'
]);
})
);
self.skipWaiting();
});
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys => Promise.all(
keys.filter(k => k.startsWith(CACHE_PREFIX) && k !== STATIC_CACHE && k !== DYNAMIC_CACHE)
.map(k => caches.delete(k))
))
);
self.clients.claim();
});
self.addEventListener('fetch', event => {
const req = event.request;
const url = new URL(req.url);
// 对 API 或 JSON 使用 network-first 以保证数据新鲜度
if (url.pathname.startsWith('/api/')) {
event.respondWith(networkFirst(req));
return;
}
// 对视频片段或大媒体资源,依据网络情况选择策略
if (req.destination === 'video' || url.pathname.endsWith('.mp4') || url.pathname.includes('/media/')) {
// 在慢网络下优先使用缓存(如果缓存没有,再尝试网络)
if (networkInfo.effectiveType && ['2g','slow-2g','3g'].includes(networkInfo.effectiveType)) {
event.respondWith(cacheFirst(req));
} else {
// 在 4g 或更好时优先网络
event.respondWith(networkFirst(req));
}
return;
}
// 对图片:在移动网络下优先加载低分辨率资源(通过同名策略或 query)
if (req.destination === 'image') {
event.respondWith(handleImageRequest(req));
return;
}
// 其他静态资源默认 cache-first
event.respondWith(cacheFirst(req));
});
function cacheFirst(request) {
return caches.match(request).then(cached => {
if (cached) return cached;
return fetch(request).then(resp => {
return caches.open(DYNAMIC_CACHE).then(cache => {
cache.put(request, resp.clone());
return resp;
});
}).catch(() => {
// 可返回本地占位图或离线页面
return caches.match('/offline.html');
});
});
}
function networkFirst(request) {
return fetch(request).then(resp => {
// 成功就缓存并返回
const clone = resp.clone();
caches.open(DYNAMIC_CACHE).then(cache => cache.put(request, clone));
return resp;
}).catch(() => caches.match(request));
}
async function handleImageRequest(request) {
// 如果是在慢网络,尝试请求低质量版本(约定:?quality=low)
if (networkInfo.effectiveType && ['2g','slow-2g','3g'].includes(networkInfo.effectiveType)) {
const lowUrl = new URL(request.url);
lowUrl.searchParams.set('quality', 'low');
try {
const resp = await fetch(lowUrl.href);
if (resp && resp.ok) {
caches.open(DYNAMIC_CACHE).then(cache => cache.put(lowUrl.href, resp.clone()));
return resp;
}
} catch (err) {
// 失败则回退到正常缓存或网络
}
}
return cacheFirst(request);
}
关键点说明:
- 使用 postMessage 将 networkInfo 传给 Service Worker,SW 内维护当前网络状态并据此改变 fetch 策略。
- 对图片请求可通过约定参数或不同域名提供低质量图片。
- 视频分段(HLS/DASH)也可以按 bitrate 切换,或将低码率索引作为默认在移动网络下请求。
3) 缓存命名与版本管理(实现无痛更新)
- 缓存名包含前缀 + 版本号,发布新版本时更新 CACHE_VERSION。
- activate 时删除旧缓存以释放空间。
- 对于大文件(视频片段)建议单独使用动态缓存并限制条目数或总大小。
示例:清理策略(LRU 简单实现思路)
- 在 IndexedDB 中记录缓存 key 的访问时间。
- 当缓存总大小超过阈值时,删除最久未访问的条目。
4) 存储配额与监测 使用 StorageManager API 估算与持久化请求:
if (navigator.storage && navigator.storage.estimate) {
navigator.storage.estimate().then(({usage, quota}) => {
console.log(`使用: ${usage}, 配额: ${quota}`);
});
}
可以在后台定期检查并当使用率超过阈值时触发清理。
5) 资源降级与按需加载
- 图片:使用 srcset、picture 标签提供不同分辨率,并在移动网络默认选择更低分辨率。
- 视频:提供多码率 HLS/DASH,多数移动网络下默认播放低码率流。
- 延迟加载(lazy-loading)和占位图,避免一次性加载大量资源。
页面端示例(图片):
<picture>
<source srcset="/images/poster-small.jpg" media="(max-width: 600px)">
<img src="/images/poster.jpg" loading="lazy">
</picture>
同时在 JS 里监听 network-change 事件把 的 src 替换为低质量版本。
6) 服务器端配合
- 对静态资源设置合理的 Cache-Control(immutable 对于版本化资源,max-age 可设置长一些)。
- 对经常变更的 API 返回 ETag 或 Last-Modified,配合服务端短缓存策略减少不必要传输。
- 支持按需请求低质量资源(通过 query、子域或 Accept headers 区分)。
示例响应头:
- 版本化文件(如 app.abc123.js):Cache-Control: public, max-age=31536000, immutable
- 动态文件/API:Cache-Control: no-cache, must-revalidate 或 short max-age + ETag
7) 调试与监控
- 在 Chrome DevTools 的 Application > Service Workers 和 Cache Storage 检查缓存。
- 打开 Network Information 模拟不同网络情况(Throttling)。
- 上线后收集关键指标:缓存命中率、首次字节时间(TTFB)、平均流量消耗、播放失败率。可把这些数据通过埋点上报供后续优化。
完整流程举例(用户路径)
- 用户在 Wi‑Fi 打开网站,Service Worker 预缓存必要文件,页面加载高清封面与高码率视频索引。
- 用户切换到移动网络,navigator.connection 触发 change,页面与 SW 收到通知。
- SW 切到 cache-first 模式并尝试加载低质量图片/低码率视频流;页面切换到小图并展示流量提示(可选)。
- 当网络恢复(回到 Wi‑Fi 或 4g 且 downlink 较大),SW 可以在后台静默更新缓存以还原高清资源。
实战注意事项与建议要点
- 用户体验优先:在降级前给出简短提示或“省流量模式”,让用户知道发生了什么并可以手动切换。
- 兼容性处理:Network Information API 并非在所有浏览器都可用,需有兜底策略。
- 不要盲目预缓存大文件:移动网络下预缓存可能消耗用户流量。
- 明确哪些资源必须实时更新(如播放清单、广告、会员权限),对这些使用 network-first。
- 日常维护:在每次发布时增加版本号并触发缓存清理脚本。
结语与可复制的清单 可复制清单(实施步骤):
- 启用 Service Worker 并实现版本化缓存名。
- 页面端使用 navigator.connection 检测网络并向 SW 广播。
- 在 SW 实现多策略:静态资源 cache-first,API network-first,媒体根据网络动态切换。
- 为图片/视频提供多质量资源并在移动网络下默认请求低质量。
- 在 activate 阶段清理陈旧缓存并使用 StorageManager 监控配额。
- 服务端支持 Cache-Control、ETag 并按需提供低质量资源接口。
- 上线后监测缓存命中率、流量和播放失败率,持续优化。