前言

一个前后端分离的项目,前端人员需要对接后端的接口。如果在后端的接口没有开发好,或者没有测试版可以对接的情况下,前端人员也不能坐等后端接口写好后再开始开发。

一个项目的,理想情况下接口的规范应该是前后端人员在开发之前就已经协商好的,如请求内容,返回内容等。在后端接口还不能供前端人员使用的时候,前端就可以通过名为 mock 的技术,伪造接口。

核心思想就是:在开发过程中,通过 mock 来拦截发起的请求,并返回伪造的数据。

在这里我们将使用 msw 包来实现。

MSW

msw 是个 mock 工具,官网在这。用于提供 mock 功能。

原理

假设我们现在有个按钮,点击后将发起请求,向服务器获取一些数据,显示到页面上。那么当前的后端接口尚未可用,我们就可以在请求后伪造一些数据,这样看起来就像请求真实接口一样。其原理如下:

在本文中使用的示例代码,我放到了 codesandbox 上try to use mocks in react

使用

在你的项目根目录下打开终端,输入 npm install msw --save-dev 安装 msw。参数 --save-dev 是必须的,因为只在开发时使用 mock,所以要安装到 devDependencies 下。

接下来我们要告诉 msw,哪些请求我们是要拦截的。

在 src 文件夹下新建一个 mocks 文件夹,我们有关 mock 的代码都会写在这个文件夹里。我们在这个文件夹里新建一个名为 handlers.ts 的文件,在这个文件里我们将告诉 msw 要 mock 哪些接口。

  1. // src/mocks/handlers.js
  2. import { rest } from "msw";
  3. export const handlers = [
  4. // Handles a POST /login request
  5. rest.post("/login", null),
  6. // Handles a GET /user request
  7. rest.get("/user", null),
  8. ];

在上面的示例代码中,我们首先从 msw 中导入了 rest 模块,关于 RESTAPI 规范的 mock 功能都在这个 rest 模块里。可以使用 rest.[Method] 语法来定义你的 mock 请求,如示例中使用 rest.post(...) 来 mock 了一个 post 请求。这个方法需要两个参数,第一个参数 mock 的 api 地址,第二个参数是一个返回假数据的函数。

上面的示例中,我们定义了两个 mock,且返回假数据的函数是 null。为了方便演示,我们只留一个。

  1. // src/mocks/handlers.js
  2. import { rest } from "msw";
  3. export const handlers = [
  4. rest.get("/getSth", (req, res, ctx) => {
  5. return res(
  6. ctx.status(200),
  7. ctx.json({
  8. username: "admin",
  9. })
  10. );
  11. }),
  12. ];

在这里我们给第二个参数传入了函数,看该函数的三个签名的含义:

  • req:表示请求信息
  • res:用于构造假响应的方法
  • ctx:用于设置相应数据的功能类

我们看上面的代码,我们定义了一个 get 请求的 mock,api 路由为 /getSth,使用 res 函数返回假数据,使用 ctx.status(200) 告诉 res 假响应的状态码是 200,使用 ctx.json 告诉 res 假相应的内容是 json 格式,并且传入了响应内容。

我们将 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。文件内的代码不需要理会,我们只需要知道它拦截了浏览器的请求即可。

响应 mock

浏览器的拦截有了,接下来就是在拦截后,将 mock 的响应返回给浏览器。

src/mocks/ 文件夹下新建文件 browser.ts,写入如下代码:

  1. import { setupWorker } from "msw";
  2. import { handlers } from "./handlers";
  3. export const worker = setupWorker(...handlers);

我们导入了 setupWorker,这个方法用于设置 mock,你可以看到我们导入了 handlers,先前写的 mock 就在这里,将它解构传入 setupWorker,返回了一个 worker。我们将使用 worker 来启动 mock 服务。

启动

我们要在项目启动时启动 mock 服务,所以回到我们的启动文件里,如果你用的是 vite,那么启动文件应该是 main;如果你用的是我的 codesandbox 连接,那么启动项目应该是 index.tsx。我以 main 为例子,如下:

  1. import { worker } from "./mocks/browser";
  2. if (process.env.NODE_ENV === "development") {
  3. worker.start();
  4. }
  5. ReactDOM.createRoot(document.getElementById("root")!).render(
  6. <React.StrictMode>
  7. <App />
  8. </React.StrictMode>
  9. );

ReactDOM.createRoot 这一句之前启动 mock。导入 browser.ts 中的 worker,接着 worker.start() 启动即可。但是我们要注意,只需要在开发中启动 mock,所以要先判断当前环境,如果是开发环境才能启动。对应的代码就是:

  1. if (process.env.NODE_ENV === "development") {
  2. worker.start();
  3. }

到这里,简单的 mock 就已经可以使用了,我们在开发中启动项目时就会顺道启动 mock 服务,如果启动 mock 成功,你会在浏览器控制台中看到:

  1. [MSW] Mocking enabled.

测试一下

直接写一个按钮,点击后发起请求就可以了。

  1. import { useState } from "react";
  2. export default function App() {
  3. const [result, setResult] = useState("");
  4. async function handleRequest() {
  5. const res = await fetch("/getSth").then((resp) => {
  6. return resp.json();
  7. });
  8. setResult(res);
  9. }
  10. return (
  11. <div className="App">
  12. <button onClick={handleRequest}>发送请求</button>
  13. <div>请求结果:</div>
  14. <div>{result}</div>
  15. </div>
  16. );
  17. }

如上,我们发起请求后,预期中会被 mock 拦截,返回 mock 的数据。由于我们没有真实的接口,所以如果 mock 启动失败,那么请求是会报错。

在 f12 中查看请求结果如下:

成功相应了 mock 中的数据。

React简单教程-5-使用mock的更多相关文章

  1. React简单教程-6-单元测试

    前言 我想大部分人的前端测试,都是运行项目,直接在浏览器上操作,看看功能正不正常.虽然明明有测试库可以使用,但是因为"要快"的原因,让好好做测试变成了一件影响效率的事. 因为这种无 ...

  2. React简单教程-4-事件和hook

    前言 在上一章 React 简单教程-3-样式 中我们建立了一个子组件,并稍微美化了一下.在另一篇文章 React 简单教程-3.1-样式之使用 tailwindcss 章我们使用了 tailwind ...

  3. React简单教程-3-样式

    前言 在上一章 React 简单教程-2-ts 和组件参数 中我们新建的子组件 Displayer 没有样式,显得平平无奇,这一篇我们将给他美化一下. CSS 文件 一般的做法,是在你的组件级目录下新 ...

  4. React简单教程-2-ts和组件参数

    前言 在上一章:React 简单教程-1-组件 我们知道了 React 的组件是什么,长什么样,用 js 和 HTML 小小体验了一下组件.在这一章,我们将使用 typescript(简称 ts) 来 ...

  5. React简单教程-4.1-hook

    前言 虽然我们简单感受了一下 useState 的用法,但我想你还是对 React 里的 hook 迷迷糊糊的.本文我们将明确下 React 的概念. HOOK 前生今世 在我示例中,写的 React ...

  6. React简单教程-1-组件

    前言 React,Facebook开发的前端框架.当时Facebook对市面上的前端框架都不满意,于是自己捣鼓出了React,使用后觉得特别好用,于是就在2013年开源了. 我也用React开发了一个 ...

  7. React简单教程-3.1-样式之使用 tailwindcss

    前言 本文是作为一个额外内容,主要介绍 tailwindcss 的用法 tailwindcss 是一个功能类优先的 CSS 框架,我在以前的文章里有描述为什么使用功能类优先:为什么我在 css 里使用 ...

  8. react+redux教程(五)异步、单一state树结构、componentWillReceiveProps

    今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...

  9. react+redux教程(四)undo、devtools、router

    上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...

随机推荐

  1. new String比字符串池浪费空间,为什么要用它?

    对于下面程序中:ss0 = new String( "hello" );是用new()来新建对象的,存于堆中.每调用一次就会创建一个新的对象.当然从节省空间的角度来讲,肯定不如st ...

  2. ThinkCMF[仿骑呗共享单车官网]

    学习Thinkcmf内容管理系统(Thinkphp3.2.3框架)时候,用来练手的,简单的模仿骑呗官网首页,并对后台管理做了点小修改. 安装: 下载地址:https://pan.baidu.com/s ...

  3. 将PHPMailer整合到ThinkPHP 3.2 中实现SMTP发送邮件

    本内容转载出处:http://my.oschina.net/BearCatYN/blog/299192 并对以下内容做了一处说明. ThinkPHP没有邮件发送的功能,于是,我就想了想,就将PHPMa ...

  4. 讲解CPU之NUMA硬件体系以及机制(lscpu查看相关信息)

    先看看从系统层面反映出来的numa cpu信息.采样机器为实体机.80核.128内存. [root@ht2 src]# lscpu Architecture: x86_64 #x86架构下的64位 C ...

  5. oracle执行sql查询语句出现错误ORA-00942:表或视图不存在

    情况是这样,A库的用户名和表空间分别为SH , SH 把业务表SH所有数据从A库,导入到B库, 表空间为SH,用户名为SP 在B库里面执行sql查询语句出现错误ORA-00942:表或视图不存在 语句 ...

  6. 如何查看k8s相关日志

    一.看系统日志cat /var/log/messages 二.用 kubectl 查看日志 # 注意:使用Kubelet describe 查看日志,一定要带上 命名空间,否则会报如下错误[root@ ...

  7. Go xmas2020 学习笔记 07、Formatted & File I/O

    07-Formatted & File I/O. I/O steams. formatted I/O. fmt functions. file I/O. Practice ① I/O. Alw ...

  8. iNeuOS工业互联网操作系统,三维(3D)模型在线编辑应用和实时数据统计(和值、均值、众数、方差、中位数等)

    目       录 1.      概述... 1 2.      三维(3D)模型在线编辑与应用... 2 3.      实时数据统计... 4 1.   概述 此次,iNeuOS工业互联网操作系 ...

  9. 2021.11.11 EXKMP

    2021.11.11 EXKMP https://www.luogu.com.cn/problem/P5410 下标以1开头: #include<cstdio> #include<i ...

  10. 转换为布尔类型 Boolean

    1. js 代码 console.log(Boolean('')); // false console.log(Boolean(0)); // false console.log(Boolean(Na ...