Appearance
Mock Service Worker
官方网站
安装
bash
yarn add -D msw
browser.js
必须是/src/mocks/browser.js
这个路径,且内容不需修改。
js
import { setupWorker } from 'msw';
const reqAll = require.context('./modules', true, /\.js$/);
const handlers = reqAll.keys().reduce((total, key) => {
return total.concat(reqAll(key).default || reqAll(key));
}, []);
export const worker = setupWorker(...handlers);
Modules
在/src/mocks/modules/
下创建若干个模块,为方便维护,我建议完全对应/src/api/
里的目录结构。
如果需要随机的 Mock Data,可以另安装mockjs
模块。如何使用mockjs
是另外的知识,可以参考官方手册。
/utils/
目录的介绍见下文。
js
// 以 /src/mocks/modules/users.js 为例
import createIdSeries from '../utils/createIdSeries';
import createPagedListHandler from '../utils/createPagedListHandler';
var Mock = require('mockjs');
const dataList = createIdSeries(1, 87).map((id) => {
return {
id,
realName: Mock.Random.cname(),
// 测试时为了命中搜索关键词,特别设了一个字段
keyword: [1, 2, 3, 4, 5][Math.floor(Math.random() * 5)],
};
});
export default [createPagedListHandler('/prod-api/users', dataList)];
工具函数
为了便捷开发,可以在/src/mocks/utils/
下创建工具函数,比如我的 2 个工具函数:
- 生成 id 等差数列
js
// /src/mocks/utils/createIdSeries.js
export default function (from, to) {
return Array(to - from + 1)
.fill()
.map((e, i) => from + i);
}
- 生成分页列表处理器,只需传入 2 个参数,第一个是 URL 的路径部分,第二个是数据列表。
js
// /src/mocks/utils/createPagedListHandler.js
import { rest } from 'msw';
export default function (url, dataList) {
return rest.all(url, (req, res, ctx) => {
const searchParams = req.url.searchParams;
switch (req.method) {
case 'GET':
// 想要获取报错的响应,就给 URL 末尾加上 fail=1 参数
if (req.url.searchParams.has('fail')) {
return res(
ctx.json({
code: -1,
msg: 'Error',
})
);
}
// GET 分页列表
if (searchParams.has('pageNum')) {
const total = dataList.length;
let pageNum = Number(searchParams.get('pageNum'));
const pageSize = Number(searchParams.get('pageSize'));
pageNum =
pageNum <= Math.ceil(total / pageSize)
? pageNum
: Math.ceil(total / pageSize);
const start = (pageNum - 1) * pageSize;
const end = pageNum * pageSize >= total ? total : pageNum * pageSize;
let list = dataList;
// 判断是否有搜索词
for (let pair of searchParams) {
if (!['pageNum', 'pageSize'].includes(pair[0])) {
list = list.filter((v) => v[pair[0]] == pair[1]);
}
}
return res(
ctx.json({
code: 0,
msg: '',
data: {
pageNum,
pageSize,
total,
list: list.slice(start, end),
},
})
);
}
// 根据 id 取单条
else if (searchParams.has('id')) {
return res(
ctx.json({
code: 0,
msg: '',
data: dataList.find((v) => v.id == searchParams.get('id')),
})
);
}
break;
// 新增
case 'POST':
var payload = req.json();
const newId = dataList[dataList.length - 1].id + 1;
dataList.push({
id: newId,
realName: payload.realName,
keyword: payload.keyword,
});
return res(
ctx.json({
code: 0,
msg: '',
data: { id: newId },
})
);
// 修改
case 'PUT':
var payload = req.json();
const row = dataList.find((v) => v.id == payload.id);
for (let key in payload) {
row[key] = payload[key];
}
return res(
ctx.json({
code: 0,
msg: '',
data: { id: row.id },
})
);
// 删除
case 'DELETE':
const id = Number(searchParams.get('id'));
const index = dataList.findIndex((v) => v.id === id);
dataList.splice(index, 1);
return res(
ctx.json({
code: 0,
msg: '',
data: { id },
})
);
}
});
}
/public/
目录写入文件
在项目根目录执行下方命令,它会给/public/
目录写入一个文件。
bash
npx msw init public/ --save
修改main.js
在main.js
最顶部写入:
js
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser');
worker.start({ onUnhandledRequest: 'bypass' });
}
注意事项
Service Worker 生效前提
https 协议下,证书必须合法才能生效。
http 协议下,域名必须是
localhost
才能生效。