为已有的react项目配置mock service worker

706 阅读4分钟

背景

前端项目经常需要在本地使用 mock 数据,因为有些特殊数据会进行一些特殊的处理。在项目运行的本地环境下,如果使用dev环境的后端接口会需要使用后端真实的数据,很麻烦,所以需要进行mock。

选择mock service worker的原因是因为它可以模拟网络延迟,模拟状态码,几乎覆盖了项目所需要的所有 mock情况。

安装步骤

安装库

指令如下:

npm install msw --save-dev
# or
yarn add msw --dev

建立 mock 文件夹

在src目录下定义mock目录,里面新建一个handlers文件。如果项目的服务很多的话,可以为每个类型的服务请求都建立一个handlers,最后统一导出。

mkdir src/mocks

touch src/mocks/handlers.js

定义 mock 数据

这一步就是可以通过在前端定义需要的数据,来达到 mock 的目的了。 文档里给的示例如下:

// src/mocks/handlers.js
import { rest } from 'msw'

export const handlers = [
  rest.post('/login', (req, res, ctx) => {
    // Persist user's authentication in the session
    sessionStorage.setItem('is-authenticated', 'true')

    return res(
      // Respond with a 200 status code
      ctx.status(200),
    )
  }),

  rest.get('/user', (req, res, ctx) => {
    // Check if the user is authenticated in this session
    const isAuthenticated = sessionStorage.getItem('is-authenticated')

    if (!isAuthenticated) {
      // If not authenticated, respond with a 403 error
      return res(
        ctx.status(403),
        ctx.json({
          errorMessage: 'Not authorized',
        }),
      )
    }

    // If authenticated, return a mocked user details
    return res(
      ctx.status(200),
      ctx.json({
        username: 'admin',
      }),
    )
  }),
]

可以看到该文件导出了一个handler,这个handler里面定义了两个 mock 接口,分别是/login的 POST请求,和/user 的 GET 请求。每一个rest的前一个参数是路由,后一个参数是一个箭头函数。

该箭头函数有三个参数,分别是req,res,ctx,官方文档对其的定义如下:

-   `req`, an information about a matching request;
-   `res`, a functional utility to create the mocked response;
-   `ctx`, a group of functions that help to set a status code, headers, body, etc. of the mocked response.

可以看到这三个参数的作用分别是:

  1. 本地发送请求的对应
  2. 创建本地 mock 响应的函数,用来创建具体 mock 的状态码,网络请求 headers
  3. 返回的具体内容等的响应内容

能够获取req的好处就是,可以在本地动态地根据请求来返回不同的响应,比如我现在mock了一个接口,这个接口需要一个参数,当参数是 1 的时候返回成功,即视为一个成功的请求,http 状态码是 200;当参数是其他的时候返回失败,即视为一个失败的请求,http 状态码是 400。 举例如下:获取参数param可以通过下面这样的方式:

const param = new URL(req.url).searchParams.get('param');

然后在箭头函数中进行param的判断:

      if (param === 1) {
        return res(ctx.status(400), ctx.json({}));
      } else {
        return res(ctx.status(200), ctx.json({}));
      }

集成你的 mock 数据

这一步我的项目是使用react和vite搭建的,所以我的集成方法会和这两个框架有关。 Mock Service Worker是通过注册 Service Worker 来拦截请求的,但我们不需要写任何worker的代码,而是通过复制一份Mock Service Worker分发的worker来实现的。 而我们复制文件的指令如下:

npx msw init <PUBLIC_DIR> --save

如果项目是通过Create React App 建立的,那么该指令对应的就是:

npx msw init public/ --save

做完这个之后其实可以看到,我们的package.json文件里面多了一段内容:

  "msw": {
    "workerDirectory": "public"
  }

这个应该就是msw为我们添加的。

新建一个worker实例

在 mock 文件夹下面建一个browser.js文件:

touch src/mocks/browser.js

内容如下:

// src/mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'

// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers)

这段代码的内容可以视为在新建一个worker

使用 mock 数据

最后一步就是进行环境的判断,这一步可以用不同的方法进行,我是通过在vite的dev环境里面配置的vite变量来获取当前项目运行的环境的。

当判断出项目运行在本地环境的时候,就使 msw 生效。

官方示例代码如下:

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}

ReactDOM.render(<App />, document.getElementById('root'))

这个判断一般是在app文件,index文件,main文件里面做的。

这一步完成之后,就可以在本地运行项目,使用自己的 mock 数据了。

彩蛋

最近在给项目安装msw,但是mock没有生效,一直404,这里放上我的调试过程。

  1. 在 public 文件夹下面的 mockServiceWorker 文件中加上打印,发现有打印内容,说明Service Worker是正常的
  2. 查看请求,发现url没有异常
  3. 因为项目在localhost之后加了一层url,对比之前的 mock 写法,发现是在react main文件配置的时候写错了,正确代码如下:
if (ENV === 'local') {
    await worker.start({
      serviceWorker: {
        url: `/${[第二层路由]}/mockServiceWorker.js`,
      },
    });
  }

refer:

  1. mswjs.io/docs/gettin…
  2. github.com/mswjs/msw/i…