2.1 安装、worker 脚本与启动
本章完成三件事:安装依赖 → 生成 worker 脚本 → 在应用入口启动。跟着做完,你的第一个请求就会被拦截。
1. 安装
bash
pnpm add msw
# GraphQL 支持需要额外安装 peer 依赖 graphql
pnpm add graphqlMSW 3 按协议分包导入,安装的包体积由你实际用到的入口决定:
ts
import { http, HttpResponse, passthrough } from "msw";
import { setupWorker } from "msw/browser"; // 仅浏览器
import { setupServer } from "msw/node"; // 仅 Node / Vitest
import { graphql } from "msw/graphql"; // GraphQL
import { ws } from "msw/ws"; // WebSocket2. 生成 worker 脚本
MSW 需要把一个官方提供的 Service Worker 文件放到站点根目录,它必须与应用同源:
bash
npx msw init public/ --save
# ✔ Mock Service Worker successfully copied!生成的 public/mockServiceWorker.js:
- 要提交到 git(它是运行时资产,别加进 .gitignore);
- 升级
msw后重新执行一次该命令保持版本一致; --save会在 package.json 写入msw.workerDirectory,让升级脚本能自动找到目录。
Vite / VitePress / Vue CLI / Create React App 的静态目录都叫
public/; Next.js 用public/,Angular 用src/。以构建工具文档为准。
3. 写第一个 handler
ts
// src/mocks/handlers.ts
import { http, HttpResponse } from "msw";
// 建议用通配源 "*/api/users":浏览器与 Node 测试用同一份 handler 都能匹配
export const handlers = [
http.get("*/api/users", () => {
return HttpResponse.json([
{ id: 1, name: "请求小邮差", role: "admin" },
]);
}),
http.post("*/api/users", async ({ request }) => {
const body = (await request.json()) as { name?: string };
if (!body.name) {
// 统一错误信封:422 + 自定义 code
return HttpResponse.json(
{ error: { code: "VALIDATION_FAILED", message: "name 必填" } },
{ status: 422 },
);
}
return HttpResponse.json({ id: 2, ...body }, { status: 201 });
}),
];为什么路径写
*/api/users而不是/api/users? MSW 3 的 Node 拦截器不会对相对路径做 origin 补全,相对路径只在浏览器中可用。 通配源(*)在浏览器和 Node 中语义一致,一套 handler 到处跑。
4. 浏览器入口启动
tsx
// src/main.tsx(React)/ src/main.ts(Vue)
import { setupWorker } from "msw/browser";
import { handlers } from "./mocks/handlers";
async function bootstrap() {
// 生产式写法:开发环境才启用 mock;本教程示例为了演示,所有环境都启用
if (import.meta.env.DEV) {
const worker = setupWorker(...handlers);
await worker.start({
serviceWorker: { url: "/mockServiceWorker.js" },
onUnhandledFrame: "warn", // 未命中的请求:bypass(默认) | warn | error
});
}
// 务必 await 之后再渲染,否则首屏请求可能早于拦截
createRoot(document.getElementById("root")!).render(<App />);
}
void bootstrap();worker.start() 的常用选项:
| 选项 | 含义 |
|---|---|
serviceWorker.url | worker 脚本 URL,默认 /mockServiceWorker.js |
onUnhandledFrame | 未匹配请求/帧的策略:"bypass" 放行、"warn" 控制台警告、"error" 直接报错 |
quiet | true 时不打印请求日志横幅 |
5. 验证
启动应用后打开 DevTools:
- Console 应出现
[MSW] Mocking enabled(worker 注册成功); - Application → Service Workers 能看到
mockServiceWorker.js处于 activated; - Network 面板中
/api/users请求的Initiator列指向 worker,响应大小、状态码一切如常。
下面这个控制台就在当前文档页里运行(本站点也启动了同一个 worker)——试着把路径改成 /api/status/404 再发送:
第一个被拦截的请求
6. 可选:msw/vite 零文件集成
MSW 3 还提供 Vite 插件,免生成静态文件:
ts
// vite.config.ts
import { defineConfig } from "vite";
import { msw } from "msw/vite";
export default defineConfig({
plugins: [msw({ handlers: "./src/mocks/handlers.ts" })],
});适合快速原型;本教程统一使用显式 worker 文件,因为它更贴近真实集成、便于理解 Service Worker 生命周期(见 3.2 Worker 生命周期与调试)。