Mock数据 msw
在看这个结构之前,我们要先看看默认的 mock
接口的内容都有哪些
MSW是什么?Mock Service Worker(MSW)是一个旨在浏览器和Node.js中使用的API模拟库。它能够拦截和模拟网络请求,这对开发者来说极为有用,因为它允许你在不需要实际后端服务器的情况下模拟网络响应,从而实现无缝的测试体验,在浏览器中的用法如下。
其实在应用的根目录public目录下有一个 mockServiceWorker.js
,大伙有没有疑惑这东西是干什么的?
一般来说public中存放的是公共资源,如HTML文件、图标或可公开访问的静态资源。这mockServiceWorker.js是什么? 这个文件主要是为了解决模拟数据问题而存在的,这个类库本身叫做MSW。然儿在浏览器端使用 Mock Service Worker (MSW) 需要添加 mockServiceWorker.js 文件,这主要是因为 MSW 利用了 Service Worker 技术来拦截和处理网络请求。 Service Worker 是一种在浏览器后台运行的脚本,可以拦截和修改访问和管理的网络请求。MSW 使用 Service Worker 来拦截发出的请求,并根据定义的模拟逻辑返回响应。罗列一下里面的关系如下:
- 我们的需求是在本地开发前端应用时使用相对真实的模拟服务
- 使用的是msw类库去实现
- 然儿在浏览器端使用msw需要添加mockServiceWorker.js
- 这个文件是一个预先编写的 Service Worker 脚本,其职责是在网络请求级别拦截请求。
- 所以当前文件是实现模拟服务的必要静态文件
我们来看看整体的mock结构,让后在细化里面的内容
├── _mock
│ ├── assets.js
│ ├── handlers
│ │ ├── _org.js
│ │ └── _user.js
│ ├── index.js
│ └── utils.js
import { setupWorker } from 'msw/browser';
import orgMockApi from './handlers/_org';
import userMockApi from './handlers/_user';
const handlers = [...userMockApi, ...orgMockApi];
// 创建一个模拟服务器实例worker,并导出
export const worker = setupWorker(...handlers);
setupWorker:从 msw/browser 导入的函数,用于在浏览器中设置服务工作者(Service Worker)。 handlers:从两个模块 ./handlers/_org 和 ./handlers/_user 导入的请求处理程序列表。这些处理程序用于拦截并模拟相应的 API 请求。 worker:创建并导出了一个服务工作者实例,该实例使用所有定义的请求处理程序来拦截和模拟 API 请求。
// 启动模拟服务器
worker.start();
工作原理:当在项目中调用 worker.start() 时,会发生如下几个步骤:
- MSW 通过 mockServiceWorker.js 脚本在浏览器中注册一个 Service Worker。这个过程涉及到将 mockServiceWorker.js 文件作为 Service Worker 安装到浏览器中。
- 一旦注册成功,这个 Service Worker 就开始拦截页面发出的所有或特定的 HTTP 请求(取决于如何配置 MSW)。
- 对于拦截的每个请求,Service Worker 会根据定义的处理逻辑生成响应。这包括根据模拟的定义返回数据、错误或其他网络响应。
- 由于所有的拦截和数据模拟都是在 Service Worker 中完成的,它不会侵入或修改应用的实际代码。这使得模拟过程对应用透明,且易于启用或禁用。
使用模拟的API
一旦服务工作器启动,所有定义的请求处理程序将自动拦截对应的网络请求,并返回模拟的响应。 例如,当你的应用尝试访问 /api/user,MSW 将拦截这个请求并返回你在处理程序中定义的模拟响应。
tip: 那什么是 Service Worker?是一种运行在浏览器背后的脚本,允许开发人员以编程方式控制缓存和网络请求的技术,使网站能够提供更丰富的离线体验和性能优化。
orgMockApi
import { http, HttpResponse } from 'msw';
import { ORG_LIST } from '@/_mock/assets';
import { OrgApi } from '@/api/services/orgService';
const orgList = http.get(`/api${OrgApi.Org}`, () => {
return HttpResponse.json({
status: 0,
message: '',
data: ORG_LIST,
});
});
export default [orgList];
http 和 HttpResponse:从 msw 导入,用于创建请求处理程序和生成 HTTP 响应。 ORG_LIST:导入的组织列表数据,用于模拟 API 响应数据(是一组默认的写死的数据内容) OrgApi:包含组织相关 API 路径的枚举或对象。
export enum OrgApi {
Org = '/org',
}
orgList
http.get:定义了一个拦截 GET 请求的处理程序,URL 为 /api/org。
回调函数:模拟服务器的响应,返回 ORG_LIST 数据,状态码为 0,表示成功。
userMockApi
// 生成大量虚假(但看上去真实)数据,用于测试和开发。
import { faker } from '@faker-js/faker';
// 从 msw 导入,用于创建请求处理程序、模拟延迟和生成 HTTP 响应。
import { delay, http, HttpResponse } from 'msw';
// 包含用户相关 API 路径的枚举或对象。
import { UserApi } from '@/api/services/userService';
// 导入的用户列表数据,用于模拟 API 响应数据(包含admin和test的两个默认测试用户)
import { USER_LIST } from '../assets';
// 登录功能:定义了一个拦截 POST 请求的处理程序,URL 为 /api/signin。
const signIn = http.post(`/api${UserApi.SignIn}`, async ({ request }) => {
// 使用 await request.json() 解析请求体。
const { username, password } = await request.json();
// 在 USER_LIST 中查找匹配的用户并验证密码。
const user = USER_LIST.find((item) => item.username === username);
if (!user || user.password !== password) {
return HttpResponse.json({
status: 10001,
message: 'Incorrect username or password.', // 用户名或密码不正确
});
}
// 成功时生成 accessToken 和 refreshToken。
return HttpResponse.json({
status: 0,
message: '',
data: {
user,
accessToken: faker.string.uuid(),
refreshToken: faker.string.uuid(),
},
});
});
// 获取用户列表:定义了一个拦截 GET 请求的处理程序,URL 为 /api/user。
const userList = http.get('/api/user', async () => {
await delay(1000);
// 模拟获取用户列表的请求,延迟 1 秒后返回生成的假用户数据。
return HttpResponse.json(
Array.from({ length: 10 }).map(() => ({
fullname: faker.person.fullName(),
email: faker.internet.email(),
avatar: faker.image.avatar(),
address: faker.location.streetAddress(),
})),
{
status: 200,
},
);
});
export default [signIn, userList];
export enum UserApi {
SignIn = '/auth/signin',
SignUp = '/auth/signup',
Logout = '/auth/logout',
Refresh = '/auth/refresh',
User = '/user',
}