在 UniApp H5 开发中,使用webview加载盈帆报表预览界面时,预览界面需要加载的WebAssembly (.wasm) 文件往往承载着核心计算逻辑,体积较大。如果每次加载都从服务器拉取,不仅耗时,还会造成极大的带宽浪费。要实现 WASM 文件的“秒开”体验,最稳健的方案是构建 Nginx 服务端缓存 与 Service Worker 客户端缓存 的双重防线。
第一道防线:Nginx 服务端配置
Nginx 是资源分发的源头。正确的配置不仅能保证浏览器原生缓存生效,更是 Service Worker 能够顺利接管请求的前提。
http {
include mime.types;
default_type application/octet-stream;
# 核心:显式声明 wasm 的 MIME 类型
types {
application/wasm wasm;
}
# ... 其他配置
}
2. 配置强缓存与流式传输支持
针对 .wasm 文件,我们需要开启长缓存,并配合 V8 引擎的流式编译特性:
location ~* \.wasm$ {
root D:\\EFReport8.2\\webapps;
types {
application/wasm wasm;
}
# 强缓存 1 年(WASM 文件更新时改文件名或加版本号)
add_header Cache-Control "public, max-age=31536000, immutable";
# 内容类型
#add_header Content-Type "application/wasm";
proxy_pass_header Cache-Control;
proxy_pass_header Content-Encoding;
# 4. 【关键】关闭 Nginx 的动态 Gzip 压缩
# 因为WASM 已经是预压缩过的,Nginx 不需要也不应该再次压缩
gzip off;
gzip_static on;
}
注:immutable 指令能告诉浏览器该文件在有效期内绝不会改变,连“验证是否过期”的请求都可以省去。
第二道防线:Service Worker 缓存策略
Nginx 解决了“存”的问题,Service Worker (SW) 则解决了“取”的效率问题。对于 WASM 这种一旦下载就极少变动的资源,“缓存优先(Cache First)” 是最佳策略。
// sw.js
const WASM_CACHE_NAME = 'uniapp-wasm-cache-v1.0.0';
// 1. 安装阶段:可以预缓存核心 WASM 文件(可选)
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(WASM_CACHE_NAME).then((cache) => {
// 如果知道核心 wasm 文件名,可在此预缓存
// return cache.addAll(['/core/module.wasm']);
return self.skipWaiting(); // 强制激活,无需等待旧页面关闭
})
);
});
// 2. 激活阶段:清理旧版本缓存
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter(key => key !== WASM_CACHE_NAME).map(key => caches.delete(key)))
).then(() => self.clients.claim()) // 立即接管所有页面
);
});
// 3. 拦截请求:WASM 专属的“缓存优先”策略
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// 仅拦截 .wasm 文件
if (url.pathname.endsWith('.wasm')) {
event.respondWith(
caches.match(event.request).then((cached) => {
// 命中缓存,直接返回(速度极快)
if (cached) return cached;
// 未命中,走网络并写入缓存
return fetch(event.request).then((response) => {
if (!response || response.status !== 200) return response;
const responseToCache = response.clone();
caches.open(WASM_CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
}
});
第三道防线:UniApp 客户端注册与避坑
配置好 SW 后,必须在报表预览界面report.html完成注册。
// 在$(document).ready中添加
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW 注册成功:', reg.scope))
.catch(err => console.log('SW 注册失败:', err));
});
}
2. 必须遵守的“三大铁律”
HTTPS 是硬性门槛:Service Worker 只能在 HTTPS 或 localhost 下运行。如果你的 UniApp H5 部署在 HTTP 环境下,SW 将直接失效。
不要手动清除 SW 缓存:避免在业务代码中频繁调用 caches.delete() 或 uni.clearStorageSync(),这会破坏精心设计的缓存体系。
总结与验证
完成上述配置后,你可以通过 Chrome DevTools 的 Network 面板进行验证:
首次访问:状态码为200,Size显示实际文件大小。
刷新页面:Status变为200(from ServiceWorker),Size显示(disk cache)。
离线模式:勾选Network面板的Offline,刷新页面,WASM依然能正常加载。
通过 Nginx 的底层兜底与 Service Worker 的精准拦截,你的 UniApp 应用在访问报表预览界面时,将不会每次都下载wasm文件,解决了加载预览页面耗时过久的问题。