从零开始搭建一个mock服务

栏目: Json · 发布时间: 5年前

内容简介:mock数据是一件很有意义的事情,前后端可以并行开发正是得益于mock生成的假数据,趁着有空撸了个轮子记录开发过程中的关注点:使用

mock数据是一件很有意义的事情,前后端可以并行开发正是得益于mock生成的假数据,趁着有空撸了个轮子 easy-config-mock ,以下记录实现思路以及最终实现的所有代码技术细节

关注点

记录开发过程中的关注点:

如何实现mock数据的功能(技术选型)

使用 mockjs 去生成假数据(附:mock规则)

使用 express 搭建服务(附:express官网)

如何集成到脚手架中,或者说工作流中

尽可能设计得简单,使其很容易集成到现有的脚手架或者工作流中,实际上 easy-config-mock 也做到了很容易集成,只需:

const easyConfigMock = require('easy-config-mock')

new easyConfigMock({
  // 将配置文件路径传递进去,服务会自动监听文件变化并重启服务
  path: path.resolve(__dirname, 'mock.config.js')
})

如何跟项目搭配使用

推荐将mock数据的配置文件放在项目的根目录下,原因在于mock数据跟业务是紧密联系的,丢在一起容易查阅与维护,如下:

+ vue-preject
-   node_modules
-   src
    mock.config.js   // mock数据的配置文件,名字仅做示例用

如何支持更复杂的场景

mockjs 的功能很强大,可以生成随机假数据,但在业务场景非常复杂的情况下这还不够,有时为了验证显示逻辑,期望是可以定制mock接口的返回

这是可以做到的,得益于express的中间件,看一下 easy-config-mock 中的配置文件是怎么写的, 更多说明

// mock.config.js
module.exports = {
  // common选项不是必须的,可以不用有该选项,内置的配置如下,当然你也可以更改
  common: {
    // mock服务的默认端口,如果端口被占用,会自动换一个
    port: 8018,
    // 如果你想看一下ajax的loading效果,该配置项可以设置接口的返回延迟
    timeout: 500,
    // 如果你想看一下接口请求失败的效果,将rate设置成0就可以了,rate取值范围0~1,代表成功的概率
    rate: 1,
    // 默认是true,自动开启mock服务,当然你也可以通过将其设置为false,关闭掉mock服务
    mock: true
  },
  // 普通的api...
  '/pkApi/getList': {
    code: 0,
    'data|5': [{
      'uid|1000-99999': 999,
      'name': '@cname'
    }],
    result: true
  },
  // 中间件api(标准的express中间件),这里你可以书写接口返回逻辑
  ['/pkApi/getOther'] (req, res, next) {
    const id = req.query.id
    req.myData = {   // 重要! 将返回数据挂载在req.myData
      0: {
        code: 0,
        'test|1-100': 100
      },
      1: {
        code: 1,
        'number|+1': 202
      },
      2:{
        code: 2,
        'name': '@cname'
      }
    }[id]
    next()  // 最后不要忘记手动调用一下next,不然接口就暂停处理了!
  }
}

easy-config-mock的优点

  • 很容易集成到脚手架或者工作流中,并且可以自动重启服务
  • 支持自定义中间件,以满足更为复杂的业务场景
  • 基本不会侵入业务代码,只需要将接口的请求前缀改成 http://127.0.0.1:mock端口
  • 配置文件丢在项目里面利于开发与维护

实现的具体技术细节

以下是实现该轮子需要的所有技术细节了,代码仅简要表达基本思想,详情内容请看 源码

如何监听 mock.config.js 文件变化

使用 chokidar 模块

const chokidar = require('chokidar')

chokidar.watch(somepath, {
  persistent: true
}).on('change', _ => {
  // file change...
  // do some logic...
})

如何实现服务的自动重启

fork 子进程去启动 express 服务,当配置文件发生变化的时候,杀掉子进程并重启服务

const childProcess = require('child_process')

let child
// 使用子进程启动express服务
child = childProcess.fork('./server.js', [], {
  encoding: 'utf8',
  execArgv: process.execArgv
})

chokidar.watch(somepath, {
  persistent: true
}).on('change', _ => {
  // 文件发生变化后杀死子进程并重启服务
  child.kill('SIGKILL')
  child = childProcess.fork('./server.js', [], {
    encoding: 'utf8',
    execArgv: process.execArgv
  })
})

子进程如何读取到配置文件数据

程序给父进程传递的数据子进程是不知道的,可以利用父子进程之间的通信,可以参考 child_process中子进程与父进程之间的通信与断开连接

// 给子进程传递数据
child.send({
  path: path
  ...
})
// 子进程接收到数据
process.on('message', ({ path, ... }) => {
  delete require.cache[path]
  // 这里,拿到了mock数据的配置项
  const options = require(path)
})

require是有缓存的,需要先删除require的缓存,再去重新获取配置文件的数据

如何去模拟jsonp的请求

首先得知道该请求是否是jsonp,检测请求链接是否带有callback参数

let dataType
app.use((req, res, next) => {
  dataType = req.query.callback ? 'jsonp' : 'json'
  next()
})

如何延迟接口的返回

有时,我们编写了loading的效果并想验证一下

const delayRes = (time) => (req, res, next) => {
  setTimeout(function() { next() }, time)
}
// 给接口增加1秒延迟
app.use(delayRes(1000))

如何让接口返回失败

有时,我们想看下断网或者服务器出错时的效果

const successRate = (rate) => (req, res, next) => {
  if (rate > Math.random()) return next()
  return next(500)
}
// 100%返回500错误
app.use(successRate(0))
app.use((err, req, res, next) => {
  res.status(500).json({ status: 0, code: 500, msg: 'Server Error' })
})

如何允许跨域

访问的非jsonp的mock接口是跨域请求 (协议,域名,端口三者相同才为同域) ,跨域请求是禁止的,会报错,这里需要设置为允许跨域

const crossDomain = () => (req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
  if (req.method === 'OPTIONS') res.status(200) // 让OPTIONS快速返回
  next();
}
app.use(crossDomain())

最终:路由创建

const { mock } = require('mockjs')

// options是配置文件里面的api信息
Object.keys(options).forEach(path => {
  const data = options[path]

  // 如果是自定义中间
  if (typeof data === 'function') app.use(data)

  app.use(path, (req, res, next) => {
    // req中带有myData的话说明是自定义中间件,否则是普通的mock api
    const rsp = req.myData ? mock(req.myData) : mock(data)
    res.status(200)[dataType](rsp)
  })
})

补充:easy-config-mock的webpack版插件

easy-mock-webpack-plugin

其实直接用 easy-config-mock 就可以了


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Nature of Code

The Nature of Code

Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95

How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具