json-server + mock.js搭建前后端分离的mock服务

3,511 阅读4分钟

前言:

做前端的应该都知道做页面的时候,当后端已经定义好了接口,但提供不了数据服务的时候,作为前端的你搭建页面是很痛苦的。 为此搭建一个可以mock数据的本地服务是很有必要的。

用到的工具库:json-server提供服务。mockjs提供模拟的数据。

本文的目录结构如下:

一、实践

1、安装依赖

npm install json-server mockjs --D

2、编写db.json路由对应表

这是一个api路径和路径对应返回的内容组成的一个文件,比如:

{
  "user_info": {
    "id": 1000,
    "course_name": "马连白米且",
    "autor": "袁明",
    "college": "金并即总变史",
    "category_Id": 2
  }
}

上面的user_info就是你的api接口路径,后面的value值就是这个接口返回的内容.

假如你本地起了一个json-server服务,http://localhost:6666,

那么你访问http://localhost:6666/user_info得到的就是以下内容:

{
  "id": 1000,
  "course_name": "马连白米且",
  "autor": "袁明",
  "college": "金并即总变史",
  "category_Id": 2
}

但问题来了: 这样简单的定义一个db.json文件,你每次访问http://localhost:6666/user_info的时候,得到的都是同一份数据,它不会变。 这不是我们想要的效果。我们想要每次访问都得到不一样的数据。

3、编写每次都会变化的mock数据

mock/mockDB/test.js


// 引入mock.js
let Mock = require('mockjs');
let Random = Mock.Random;

// 编写一个函数,这个函数利用mock.js动态生成mock数据
// 我看到很多教程这里是直接输出一个对象的,这样每次访问得到的都是同样的数据。不符合预期,
// 我们这里用函数包装,每次访问api的时候就执行一次该函数,得到的就是新的mock数据了
function testList() {
  const monitorList = [];
  for (var i = 0; i < 3; i++) {
    monitorList.push(
      Mock.mock({
        userid: '25788869998_1562054852076593528',
        appid: Random.natural(100, 3000),
        content: Random.cparagraph(2, 4),
        timestamp: 1562054852,
      })
    );
  }
  
  // 这里返回你想要的数据格式
  return {
    success: true,
    data: monitorList,
    message: '获取数据成功',
  };
}

// 以api路径为值,将testList函数暴露出去
exports.user_info = testList;

4、编写组装db.json文件的代码

如上文所说,json-server需要一个json文件做路由配置表,格式如下:

{
  "user_info": {
    "id": 1000,
    "course_name": "马连白米且",
    "autor": "袁明",
    "college": "金并即总变史",
    "category_Id": 2
  }
}

非常注意的是: 路由配置里,api路径为key值,返回的数据为value值,这个value必须是数组或者对象。不能是函数,下面的写法是会报错的。

{
  "user_info": function () {
    return {
        "id": 1000,
        "course_name": "马连白米且",
    }
  }
}

但想要每次请求同一个接口,返回的都是不一样的数据,这个value必须是函数才行。这就是我们在mock/mockDB/test.js定义的是函数的原因。因为json-server的原理应该是:拿到访问的路径,然后通过路由配置表找到对应的value值,最后返回给用户的。如果写死成一个对象,或者数组,那么每次访问得到的都是同样的数据。

mock/db.js

将mockDB文件夹所有的mock数据文件读取出来,组装成上面路由配置表的格式,再暴露出去。 这里可以用webpack提供的require.context读取所有文件,也可以用node的fs模块读取所有文件。这里我就不展开来写了。简单说一下流程。

 // 引入mockDB文件夹下的文件,假如有以下文件
 let test1 = require('./mockDB/test.js');
 let test2 = require('./mockDB/test2.js');
 
 // 这里定义一个收集的对象
let dbJson = {
  func: {},
  json: {},
}
// 收集mock函数,在server.js会用到
dbJson.func = {
  ...test1,
  ...test2,
};

// 获取所有的api路径
let apiPath = Object.keys(dbJson.func);

// 组装json-server需要的路由表,这里为什么都是空对象呢?
// 上面说过,路由表的value必须是对象或者数组。但我们的mockDB文件夹下定义的都是mock函数,所以这里要保证路由表是正确的,就要重新组装一份符合格式的路由表。
apiPath.forEach(item => {
  dbJson.json[item] = {};
});

exports.dbJson = dbJson.json;
exports.dbFunc = dbJson.func;

5、搭建json-server本地服务

const jsonServer = require('json-server');
// 创建json-server实例
const server = jsonServer.create();
const jsonDB = require('./db');
// 将路由配置表传入,生成路由表
const router = jsonServer.router(jsonDB.dbJson);
const middlewares = jsonServer.defaults();

// 这里比较重要。
// 目的是:重新定义路由返回的数据。就是说:每访问一个路由,返回response的时候,都可以经过router.render重新定义response数据
// 因为我们在db.js里将mock函数收集到了dbJson.func对象里。
router.render = (req, res) => {
    // 根据请求的url,截取路径。
    // 例如:一般情况,res.url是/user_info?id=1234这样的格式。
    let end = req.url.indexOf('?');
    let apiName = req.url.slice(1, end) || '';
    // 根据apiName拿到对应的mock函数,然后返回mock函数生产的mock数据
    // 因为每次返回response的时候,都会执行一次该函数,所以得到的都是新的mock数据
    let response = dbJson.func[apiName] && dbJson.func[apiName]();
    res.send(response || {}));
};

server.use(middlewares);
// 导入路由
server.use(router);
// 在6666端口开服务
server.listen(6666, () => {
  console.log('JSON Server is running');
});

6、启动服务

node mock/server.js

7、结束语

这篇文章是个人的实践做法,如果有说的不对的地方,还望见谅、指正,谢谢