接口联调那些事儿

2020/12/22 MockJS测试

🌙 接口联调那些事儿

🌙 1.背景

在 2005 年,Google 通过其 Google Suggest 使 AJAX(Ajax维基百科 (opens new window)) 变得流行起来之后,前端迎来了新的纪元。

随着前后端分离,前端地位也日益提升,但是也暴露了新的问题——前后端联调。🐛

🌙 2.前后端联调

🌙 2.1 青铜阶段

犹记当年,我还是一个懵懂的前端小白,拿着后端大佬给的接口不知所措。。。留下了没有技术的😂🙈

此时,一般都会结对编程,前后端面对面、手把手(咳!),“接口定义。。。”、“字段含义。。。”。

一般复杂的接口估计需要大半天联调时间。

🌙 2.2 黄金阶段

这个阶段,一般不会结对编程了(妹子除外哈🙈, go die!)。

后端会把mock的数据copy一份,一般是一个JSON串,丢给前端,让前端自己玩儿。厉害一点的前端会启动一个Node服务(比如express),模拟后端接口的URL、methods、response等,已经非常接近真实的接口了。

// 加载 expres 模块
const express = require('express');
// 创建一个 app 对象
const app = express();
// 通过中间件监听指定的路由
app.get('/data', (req, res) => {
    res.send('hello world!世界,你好!');
    // res.end('hello world!世界,你好!')
});
// 启动服务,监听8088端口
app.listen(8088, () => {
    console.log('http://localhost:8088');
})
1
2
3
4
5
6
7
8
9
10
11
12
13

🌙 2.3 钻石阶段

此时,一般会有一个专门定义接口的后端设计(俗称SE),把接口文档设计OK,前后端根据这个接口文档去定义接口或页面。这个SE一般都是大哥大,业务和代码都很溜。

一般,前后端都玩的非常溜了,大家没必要时间浪费在接口联调上。后端大佬一般会把mock接口定义在API直通车上,或者使用其他工具,比如DocleverYapiEasyMock等。前端根据这些工具去获取所需的接口。

前端甚至可以使用MockJS,在项目中拦截真实的接口,自定义各种场景下的数据,以便覆盖各种场景,比如:页面性能测试、压力测试(数据量很大)、边缘测试(不常见的场景)等。这样一来,测试也很轻松了。

接口测试及工具传送门→

🌙 2.4 王者阶段

俗称的全栈(干),前后端一个人搞定,这样就没什么接口联调的扯🥚了!

🌙 3.推荐使用MockJS

生成随机数据,拦截 Ajax 请求 (opens new window)

  • 数据类型丰富:支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。

  • 拦截 Ajax 请求:不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据。安全又便捷

一句话,真香啊!

文档直通车 (opens new window)

🌙 3.1 安装

  • 使用Random CLI
# 全局安装
npm install mockjs -g

# 执行
random url
# => http://rmcpx.org/funzwc

# 帮助
random -h
1
2
3
4
5
6
7
8
9
  • 在项目中使用
npm install mockjs -D
1

🌙 3.2 在react-ts项目中使用

  • 在scr目录下建立mock目录,新建index.ts

  • app.ts中引入

import './mock'

// 为了在开发阶段避免部署时需要删除mock数据,建议按一下方式处理:

// 生产环境mock数据不打包
if (process.env.NODE_ENV === 'development') {
  require('./mock');
}
1
2
3
4
5
6
7
8
  • mock目录下新建test.ts
// 引入 Mock
import Mock from 'mockjs';

// 默认拦截get请求
Mock.mock(
  '、mock/test',
  {
    // 属性 data 的值是一个数组,其中含有 1 到 10 个元素
    'data|1-10': [
      {
        // 年龄1-100随机
        'age|1-100': 0,
         // 性别随机枚举一个
        'gender|1': ['男','女','未知'],
        // 随机中文名
        'name': '@cname',
        // 随机名字
        'nickName': '@name',
        // 随机生日
        'birthday': '@date',
        // 随机省份
        'province': '@province',
      },
    ],
  }
);

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

注意:'age|1-100': 0,|前后不可有空格。

然后在mock/index.ts中引入:

import './test'
1

🌙 3.3 拦截请求

  • API解读:参考Mock.mock(rurl?, rtype?, template|function(options)) (opens new window)

    • rurl:可选,表示需要拦截的 URL,可以是 URL 字符串或 URL 正则。例如 /\/domain\/list\.json//domian/list.json
    • rtype:可选,表示需要拦截的 Ajax 请求类型。例如 GET、POST、PUT、DELETE 等。
    • template: 可选,表示数据模板,可以是对象或字符串。例如 { 'data|1-10':[{}] }@EMAIL
    • function(options):可选,表示用于生成响应数据的函数。options指向本次请求的 Ajax 选项集,含有 urltypebody 三个属性,参见 XMLHttpRequest 规范 (opens new window)
  • 拦截GET请求:

import Mock, { Random } from 'mockjs';

Mock.mock(
  '/mock/test/get',
  'get',
  () => {
    const data = [];
    for (let i = 0; i < 5; i++) {
      data.push({
        image: Random.image('1200x140',getRandomColor(),'mock随机图片测试'),
        id: Random.id(),
        picLink: Random.url(),
        name: Random.name(),
      });
    }

    return data;
  }
);

function getRandomColor() {
  return (
    '#' +
    '0123456789abcdef'
      .split('')
      .map(function(v, i, a) {
        return i > 5 ? null : a[Math.floor(Math.random() * 16)];
      })
      .join('')
  );
}

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
29
30
31
32
  • 拦截POST请求:
import Mock from 'mockjs';

// 拦截post请求
Mock.mock('/mock/test/post', 'post', {
  'status|1': [200, 500],
  'data|1': ['OK', 'ERROR', ''],
});

1
2
3
4
5
6
7
8
  • 拦截带参数的请求,如/mock/post/user?id=12656
import Mock from 'mockjs';

let data = {
    "code": 0,
    "data": {
      "fullName": "@CNAME",
      "userId": "@id",
    }
};
Mock.mock(RegExp('/mock/post/user' + '.*'), "get", (options) =>{
    // 调试
    console.debug(data, options);
    return Mock.mock(data);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

如何处理好前后端分离的 API 问题 (opens new window)