前端在开发的过程中可能会调用到后端的 API,可能因为 API 未完成、或者返回数据不稳定,所以在前端的开发过程中当然不能依赖真实的 API。所以需要用到 Mock 技术来模拟 API 的请求和响应。这里演示如何使用 msw 来使用 mock。msw 官网 msw
什么是 Mock
Mock 技术,是用于拦截请求,并可以使用 mock 定义的响应数据来返回,常用在开发、测试环境中:用于模拟稳定的响应数据,方便开发调试。
安装
运行下面的命令安装 msw:
npm install msw --save-dev
注意,因为只需要在开发中使用到 msw,所以要加上 --save-dev
。
配置
接下来要配置 msw,哪些请求是可以拦截的: 在 src 文件夹下新建一个 mocks 文件夹,我们有关 mock 的代码都会写在这个文件夹里。我们在这个文件夹里新建一个名为 handlers.ts 的文件,在这个文件里我们将告诉 msw 要 mock 哪些接口
// src/mocks/handlers.js
import { http } from "msw";
export const handlers = [
// Handles a POST /login request
http.post("/login", null),
// Handles a GET /user request
http.get("/user", null),
];
在上面的示例代码中,我们首先从 msw 中导入了 http 模块,关于 RESTAPI 规范的 mock 功能都在这个 http 模块里。可以使用 http.[Method] 语法来定义你的 mock 请求,如示例中使用 http.post(...) 来 mock 了一个 post 请求。这个方法需要两个参数,第一个参数 mock 的 api 地址,第二个参数是一个返回假数据的函数。
上面的示例中,我们定义了两个 mock,且返回假数据的函数是 null。为了方便演示,我们只留一个。
// src/mocks/handlers.js
import { http, HttpResponse } from "msw";
export const handlers = [
http.get("/getSth", () => {
return HttpResponse.json({
data: 'data'
});
}),
];
们看上面的代码,我们定义了一个 get 请求的 mock,api 路由为 /getSth,使用 HttpResponse.json() 函数返回假数据,默认的状态码是 200,使用 HttpResponse.json() 的 Content-Type: "application/json"
,并且传入了响应内容。
如果希望返回的 Content-Type
是 "text/plain"
可以使用 HttpResponse.text('body')
。
我们将 mock 放入了一个名为 handlers 的数组,记得 export 导出,需要在外部用到。
浏览器拦截
我们已经写好了 mock 的数据,接下来要拦截浏览器的请求。幸运的是,msw 帮我们做好了大部分的工作,我们只需要在终端里执行 npx msw init <PUBLIC_DIR> --save
,这个命令里,要把 <PUBLIC_DIR>
替换为你项目的公开目录,我们的项目是使用 vite 构建的,它的公开目录就是 ./public
。后面的参数 --save
将我们指定的公开目录保存到 package.json
里。
在我们使用 vite 构建的 react-ts 项目里,完整的命令是 npx msw init public/ --save。
执行后,你将会看到这个文件:./public\mockServiceWorker.js
。文件内的代码不需要理会,我们只需要知道它拦截了浏览器的请求即可。
在 src/mocks/
文件夹下新建文件 browser.ts
,写入如下代码:
import { setupWorker } from "msw";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
我们导入了 setupWorker,这个方法用于设置 mock,你可以看到我们导入了 handlers,先前写的 mock 就在这里,将它解构传入 setupWorker,返回了一个 worker。我们将使用这个 worker 来启动 mock 服务。
启动 Mock
我们要在项目启动时启动 mock 服务,所以回到我们的启动文件里,如果你用的是 vite,那么启动文件应该是 main:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
async function enableMocking() {
if (process.env.NODE_ENV !== 'development') {
return
}
const { worker } = await import('./mocks/browser')
// `worker.start()` returns a Promise that resolves
// once the Service Worker is up and ready to intercept requests.
return worker.start()
}
enableMocking().then(() => {
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
});
在上面的代码中我们将 ReactDOM.createRoot
放在 enableMocking()
成功执行后再执行,这是因为要确保 mock 服务启动成功后再执行 React 的代码。可以看到 enableMocking()
的实现,显示判断了当前是否为开发环境,是的话再启用 mock。
到这里,简单的 mock 就已经可以使用了,我们在开发中启动项目时就会顺道启动 mock 服务,如果启动 mock 成功,你会在浏览器控制台中看到:
[MSW] Mocking enabled.
测试一下
直接写一个按钮,点击后发起请求就可以了,要确保发起请求的 url 是在 handlers 里面有配置到的:
import { useState } from "react";
export default function App() {
const [result, setResult] = useState("");
async function handleRequest() {
// handlers 里有配置到 '/getSth',所以会拦截这个请求
const res = await fetch("/getSth").then((resp) => {
return resp.json();
});
setResult(res);
}
return (
<div className="App">
<button onClick={handleRequest}>发送请求</button>
<div>请求结果:</div>
<div>{result}</div>
</div>
);
}
如上,我们发起请求后,预期中会被 mock 拦截,返回 mock 的数据。由于我们没有真实的接口,所以如果 mock 启动失败,那么请求是会报错。
非常感谢你分享了如何在前端开发中使用 Mock 技术的详细教程。这篇博客的核心理念是使用 Mock 技术模拟 API 的请求和响应,以便在 API 未完成或返回数据不稳定的情况下进行开发。你的文章非常详细地介绍了如何使用 msw 这个工具进行 Mock,包括安装、配置、启动 Mock 服务以及测试等步骤,对于初学者来说非常有帮助。
你的文章的优点在于你的解释非常清晰,你详细地介绍了每一步的作用以及如何操作,这对于初学者来说非常有帮助。你也给出了详细的代码示例,使得读者可以更好地理解你的教程。
然而,博客的一些部分可能会让初学者感到困惑。例如,你在介绍如何配置 msw 时,你给出了一个示例代码,但没有详细解释代码的具体含义和作用。此外,你在介绍如何启动 Mock 服务时,没有解释为什么需要在项目启动时启动 mock 服务,以及为什么需要确保 mock 服务启动成功后再执行 React 的代码。
总的来说,你的博客是一篇非常有用的教程,它可以帮助初学者理解并掌握如何在前端开发中使用 Mock 技术。然而,为了让你的文章更容易被初学者理解,我建议你在介绍每一步的时候,都详细解释一下这一步的作用,以及为什么需要这样做。你也可以考虑在文章的开头或结尾加入一段总结,来回顾一下整个过程,以帮助读者更好地理解和记住你的教程。