Skip to content

3.2 Service Worker 生命周期与调试 ​

理解 worker 的生命周期,才能解释"为什么我改了 handler 没生效""为什么首次刷新不拦截"这类问题。

注册到激活 ​

worker.start() 内部经历标准 Service Worker 生命周期:

register(mockServiceWorker.js)
        │
        ▼
   installing  ── 下载并解析脚本,版本由文件内容决定
        │
        ▼
   installed(等待) ── 旧 worker 仍控制页面时,新 worker 在队列等待
        │  (skipWaiting/clients.claim 后立即接管,MSW 已处理)
        ▼
   activating → activated  ── 开始拦截 fetch 事件
        │
        ▼
   fetch / message 事件循环(你的 handlers 在这里执行)
        │
        ▼
   redundant  ── 被新脚本取代或注销

MSW 的 worker 脚本内置了 skipWaiting + clients.claim,因此注册后立刻生效,不用手动关标签页。

为什么必须 await start() ​

ts
// ❌ 首屏请求可能在 worker activated 之前发出,直接穿透到网络(404)
worker.start();
fetch("/api/me");

// ✅ start() resolve 时 worker 已激活
await worker.start();
fetch("/api/me");

本教程的 React/Vue 示例都在入口 await startMockWorker() 之后才挂载根组件。

handler 顺序 = 匹配优先级 ​

ts
setupWorker(
  http.get("*/api/users/:id", getUser),   // 先注册,先匹配
  http.get("*/api/*", fallback),          // 兜底放最后
);
  • resolver 返回了 Response:匹配结束;
  • resolver 什么都没返回(undefined):继续向下找下一个匹配的 handler(叫 passthrough-by-omission);
  • 显式调用 passthrough():直接放行到真实网络:
ts
import { http, passthrough } from "msw";

http.get("*/assets/*", () => passthrough()),  // 静态资源不 mock
http.get(/.*/, () => passthrough()),          // 其余全部放行

运行时增删 handler ​

ts
// 测试或调试场景非常有用:临时加一个 handler
worker.use(
  http.get("*/api/users", () => HttpResponse.json([{ id: 999 }])),
);

// 恢复到 setupWorker 时的初始集合
worker.resetHandlers();

// 移除通过 use() 加入的(restoreHandlers 与 resetHandlers 的区别见官方 API)
worker.restoreHandlers();

onUnhandledFrame:未命中策略 ​

MSW 3 用 onUnhandledFrame 统一了 HTTP 与 WebSocket:

ts
worker.start({ onUnhandledFrame: "error" });
取值行为适用
"bypass"(默认)静默放行到真实网络开发期,页面有真实静态资源/埋点
"warn"Console 警告但放行排查"为什么没匹配上"
"error"抛错测试里强制"所有请求必须被声明"

也可以传函数做精细化控制(比如只对 /api 报错、埋点请求放行)。

调试三板斧 ​

  1. Console 横幅:[MSW] 0.xx.x mocking enabled.(quiet 关闭时)与每条命中日志。
  2. Network 面板:请求真实存在,响应头里可以看到 MSW 标记;看 Initiator 能确认是否走 worker。
  3. Application → Service Workers:手动 Update / Unregister / Offline 模拟。

常见问题:

现象原因与处理
[MSW] Failed to registerworker 路径错或同源策略问题;确认脚本能通过 /mockServiceWorker.js 访问
handler 改了不生效热更新偶发;DevTools → Service Workers → Update,或硬刷新
Node 下相对路径不匹配Node 不做 origin 补全,handler 路径用 */api/... 通配源
首次加载有一个请求漏网没 await worker.start() 就发请求
worker 版本升级后行为怪重新 npx msw init public/,并 Unregister 旧 worker

Node 端没有 Service Worker ​

setupServer 在 Node 中由 @mswjs/interceptors 直接劫持 fetch / http / xmlhttprequest(兼容层),没有生命周期一说:

ts
server.listen({ onUnhandledFrame: "error" }); // beforeAll
server.resetHandlers();                       // afterEach,防止测试互相污染
server.close();                               // afterAll

详细测试实践见 6.2 Node 环境与单元测试。