MSW 在前端项目中的正确打开方式:从“造数据”到“定义接口”

为什么要重新理解 MSW

在很多项目里,MSW 被当成了:

  • 一个 mock 数据工具
  • 一个本地调试的临时方案
  • 一个替代 mock.js 的库

但在实际工程中,如果这样使用 MSW,价值会非常有限,甚至会制造新的混乱。

我们最终达成的共识是:

MSW 不是用来“造假数据”的,而是用来“定义接口行为”的。


MSW 的合理定位

在我们的体系中:

  • MSW ≠ mock 数据生成器
  • MSW ≠ 测试专用工具
  • MSW = 可执行的接口契约

它承担的职责只有三件事:

  1. 明确 URL 与 HTTP Method
  2. 明确请求与响应结构
  3. 明确错误码与异常场景

一个最小但正确的 MSW handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { http, HttpResponse } from 'msw'

export const whoamiHandler = http.get('/auth/whoami', ({ request }) => {
const token = request.headers.get('Authorization')

if (!token) {
return HttpResponse.json(
{
code: 1002,
message: '未认证',
trace_id: 'mock'
},
{ status: 401 }
)
}

return HttpResponse.json({
code: 0,
message: 'ok',
data: {
type: 'admin',
id: '1',
name: 'Admin'
},
trace_id: 'mock'
})
})

注意几点:

  • 永远返回完整 ApiResponse
  • 错误分支和成功分支都要写
  • 不关心真实数据库,只关心协议

MSW 目录结构设计

一个可维护的 MSW 目录应该是按接口域拆分,而不是按页面拆分

1
2
3
4
5
6
7
8
9
src/mocks/
├── handlers/
│ ├── auth.ts
│ ├── user.ts
│ └── index.ts
├── factories/
│ ├── user.ts
│ └── pagination.ts
└── browser.ts

handlers

  • 描述接口行为
  • 不直接写大量数据
  • 只处理协议与分支逻辑

factories

  • 负责生成结构正确的数据
  • 可复用
  • 不关心接口 URL

handlers 应该写什么,不该写什么

应该写

  • 参数校验失败
  • 鉴权失败
  • 资源不存在
  • 业务限制错误

不应该写

  • 复杂随机逻辑
  • 模拟数据库
  • 页面专属分支

如果 handler 中出现大量 Math.random(),基本说明职责已经跑偏。


一个典型的 CRUD handler 写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
export const userHandlers = [
http.get('/users', ({ request }) => {
const page = Number(new URL(request.url).searchParams.get('page') ?? 1)

return HttpResponse.json({
code: 0,
message: 'ok',
data: {
list: createUserList(10),
total: 100,
page,
pageSize: 10
},
trace_id: 'mock'
})
}),

http.post('/users', async ({ request }) => {
const body = await request.json()

if (!body.name) {
return HttpResponse.json(
{ code: 1001, message: '参数错误', trace_id: 'mock' },
{ status: 400 }
)
}

return HttpResponse.json({
code: 0,
message: 'ok',
data: { id: 'new_id' },
trace_id: 'mock'
})
})
]

MSW 与页面的关系

一个非常重要的原则:

页面不应该知道自己在使用 MSW。

这意味着:

  • 请求方式与真实接口完全一致
  • 错误处理逻辑完全一致
  • try / catch 行为一致

MSW 的存在对页面是透明的。


如何新增一个接口(标准流程)

当页面需要一个新接口时:

  1. 在 MSW 中先定义 handler
  2. 明确请求参数与返回结构
  3. 明确错误码
  4. 页面基于该接口开发
  5. 将结构登记到 OpenAPI 文档
  6. 后端实现接口

禁止直接根据后端 Swagger 写页面。


MSW 与 OpenAPI 的关系

  • MSW 是行为定义
  • OpenAPI 是结构与文档定义

在实践中:

  • MSW 是开发驱动
  • OpenAPI 是交付物
  • Swagger 是后端产出

常见误区

把 MSW 当成“前端数据库”

这会导致:

  • handler 极度复杂
  • 行为不可预测
  • 后端无法对齐

handler 按页面拆分

接口属于领域,不属于页面。


什么时候不该用 MSW

  • 单页 Demo
  • 一次性活动页
  • 已完全稳定、无演进空间的接口

MSW 适合持续演进的系统


总结

MSW 的真正价值不在于“快”,而在于:

  • 提前冻结接口语义
  • 降低协作摩擦
  • 提供可执行的接口契约

当你开始用 MSW 讨论接口结构,而不是写假数据时,它才真正发挥了价值。

MSW 在前端项目中的正确打开方式:从“造数据”到“定义接口”

https://www.f2iclo.cn/2026/02/10/howtousemsw01/

作者

小郑

发布于

2026-02-10

更新于

2026-02-10

许可协议

评论