前言

mock 工具的使用以及拓展

形式

开启 mock 有两种形式 环境变量和注解

通过环境变量开启 mock(生产阶段优选)

这个需要 env 里面是否包含 mock 环境的判断
不过一旦构建好就改不了了 mock

通过注解开启 mock(开发阶段优选)

项目默认开启 mock(main.ts 中注入)
不需要的时候直接注释掉即可

综上的新方法

开发环境:默认 mock 环境

1
2
3
VUE_APP_MODE=mock
VUE_APP_URL=x'x'x
VUE_APP_MARK_TEXT=开发环境

生产环境

1
2
3
VUE_APP_MODE=product
VUE_APP_URL=xxxx
VUE_APP_MARK_TEXT=生产环境

main.ts

1
2
3
4
// 通过注释动态控制开发环境是否需要mock
if (process.env.VUE_APP_MODE === "mock") {
// require("@/mock");
}

mock 基本使用

http://mockjs.com/examples.html
常用:

1
2
3
4
'data|10':[],// 表示十个data
"id|+1": 0, // id从0开始自增1
'rate|0-5',// rate 从0-5范围随机获取
'name|1-100.3':1 // 包含三位小数

mock 根据不同的请求参数返回不同的结果

由于普通的 mock 其实不需要参数,但是 mock 本身也可以接收参数,分为两种情况
先讲一下原理 一般 mock 方法是这样写的:

1
Mock.mock(url, method, (opts) => {});

其中 url 是拦截的地址 method 是请求方法 opts 则是一个对象
关键在于 opts 它的类型定义如下

也就是它会暴露三个参数 一个是拦截 url 一个是请求方法 一个是 body
如果是 GET 请求 那么请求体则在 opts.url 中,需要单独分割出来,方法在下面看
如果是 POST 请求 那么请求体就是在 body 中,也是对象 直接用就好
那么基于上面 就可以拿到对应的参数 进行返回

将 url 中的参数转对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 获取url中的参数
* @param url url
* @returns 参数
*/
const getUrlSearchToObject = <T>(
url = window.location.search
): Record<keyof T, string> => {
const urlStr = url.split("?")[1];
const paramsArr = urlStr.split("&");
return paramsArr.reduce((pre, cur) => {
const arr = cur.split("=");
const [key, value] = arr;
pre[key as keyof T] = value;
return pre;
}, {} as Record<keyof T, string>);
};

mock 封装

举个例子
mock/module/music.ts 用于 mock 一个接口 返回 url type 和一个 cb cb 包含上述的结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
export const musicMockEntity: Record<
string,
{
url: string;
type: string;
cb: any;
}
> = {
moduleStatusList: {
url: "/mock/api/getModuleStatusList",
type: "get",
cb: (opts: MockjsRequestOptions) => {
console.log(opts);
return {
code: 0,
msg: "",
data: {
statusList: [
{
business_status: "1-1",
name: "投票中",
},
],
},
};
},
},
};

mock/index.ts 用于全局定义一个 mock 实例 通过导入模块的方式 去拦截对应的请求并返回 这里的嵌套了一层 Mock.mock 会不太灵活 其实 应该放在上面 cb 返回值 因为有时候 cb return 的东西不一定要经过 Mock.mock 嵌套,有可能直接是一个 json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Mock, { MockjsRequestOptions } from "mockjs";
import { musicMockEntity } from "./module/music";

const modules = [musicMockEntity];
Mock.setup({
timeout: "200-600",
});
modules.forEach((module) => {
Object.keys(module).forEach((key) => {
const { url, type, cb } = module[key];
// 用正则是因为直接写地址的话 后续的?xxx=就匹配不到
Mock.mock(new RegExp(url), type, (opts: MockjsRequestOptions) => {
console.log(opts, "opts");
return Mock.mock(cb(opts));
});
});
});

在 apifox 中使用 mock

场景

一般后端出接口文档 出在 apifox 上 所以可以直接使用 apifoxmock 然后在项目中导入
缺点是它并没有携带拦截功能
直接 mock

  • 方式 1 通过生成的 mockjson 直接导入使用
  • 方式 2 通过 mock 地址来注入

    更改对应接口的地址 注意 axios 是可以通过 url 覆盖 baseUrl 的

    日常开发更推荐方式 2 因为方式 2 不需要额外的文件产出,就是 url 丑了点

通过服务转发/注入 axios 来 mock

上述方式二带来的方法是 url 覆盖 baseUrl 但是这样做 不好维护 mock 地址
注入 axios + 环境(推荐)
环境变量文件

1
2
3
4
5
export default {
baseUrl: process.env.VUE_APP_URL,
mockUrl: process.env.VUE_APP_MOCK_URL,
mode: process.env.VUE_APP_MODE,
};

配置 axios 然后开发的时候可以通过 isMock 参数动态更新(因为 axios 不涉及部署 webpack 是会热更新的)

1
2
3
4
5
6
7
8
9
10
// 是否开启mock
const isMock = false;
function request(axiosConfig: AxiosRequestConfig) {
const service = axios.create({
baseURL: isMock && config.mode === "mock" ? config.mockUrl : config.baseUrl, // env
// 请看vue.config.js 的devserver.proxy
// baseURL: "/api", // env
timeout: 50000,
});
...

上述方式可以达到本地开发和 mock 环境共存,通过修改参数动态注入 mock
服务转发(不推荐) 因为不能动态更新 除非用插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = defineConfig({
devServer: {
proxy: {
"/mock": {
target: process.env.VUE_APP_URL, //转发地址
changeOrigin: true, // 跨域支持
secure: false, //可选 默认对于没证书的https会拦截
pathRewrite: {
// 重写路径后的内容
"^/mock": "",
},
},
},
},
});

高级 mock

期望

类似于通过入参出参决定数据 前端可以自己 diy 数据

注意! 如果有脚本 会先走脚本 后走期望 如果有期望 则满足条件会走期望

脚本

期望的高级版本,相当于前端自己写 mock 数据,有一些 apifox 自带的语法
https://www.apifox.cn/help/app/mock/mock-custom-scripts/#%E7%A4%BA%E4%BE%8B%E4%BA%8C

结论
对比两种工具
Apifox(推荐)

  • 优势:
    • 学习成本低,且所有数据都有自带的 mock
    • 基于 mockjs 在工具上直接 mock 在工具上通过期望自定义 mock 在工具上通过脚本自定义 mock
  • 劣势:
    • 如果需要一些自定义的情况 还是要学习 mockjs
  • 如果采用了 Apifoxmock
    • 使用 apifoxmock 则 需要开启 apifox
    • 如果通过服务转发/环境的方式 则前端需要区分 mock 环境和开发环境
      Mockjs
  • 优势:
    • js 纯自己造数据 自由度高一点
  • 劣势:
    • 自带的拦截服务有时候会造成 bug
    • 因为文档的原因脱离不开 apifox
  • 如果采用 mockjs
    • mockjs 适合于 只需要部分接口 mock 的情况
    • 前端的本地开发环境都是 mock 环境了 因为它自带了拦截