mock数据是一件颇有意义的事情,先后端能够并行开发正是得益于mock生成的假数据,趁着有空撸了个轮子easy-config-mock,如下记录实现思路以及最终实现的全部代码技术细节javascript
记录开发过程当中的关注点:html
使用mockjs
去生成假数据(附:mock规则)vue
使用express
搭建服务(附:express官网)java
尽量设计得简单,使其很容易集成到现有的脚手架或者工做流中,实际上easy-config-mock
也作到了很容易集成,只需:node
const easyConfigMock = require('easy-config-mock')
new easyConfigMock({
// 将配置文件路径传递进去,服务会自动监听文件变化并重启服务
path: path.resolve(__dirname, 'mock.config.js')
})
复制代码
推荐将mock数据的配置文件放在项目的根目录下,缘由在于mock数据跟业务是紧密联系的,丢在一块儿容易查阅与维护,以下:webpack
+ vue-preject
- node_modules
- src
mock.config.js // mock数据的配置文件,名字仅作示例用
复制代码
mockjs
的功能很强大,能够生成随机假数据,但在业务场景很是复杂的状况下这还不够,有时为了验证显示逻辑,指望是能够定制mock接口的返回git
这是能够作到的,得益于express的中间件,看一下easy-config-mock
中的配置文件是怎么写的,更多说明github
// 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,否则接口就暂停处理了!
}
}
复制代码
http://127.0.0.1:mock端口
如下是实现该轮子须要的全部技术细节了,代码仅简要表达基本思想,详情内容请看源码web
mock.config.js
文件变化使用chokidar
模块ajax
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,检测请求连接是否带有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
就能够了
都看到这了,赏个赞👍呗~🙂😃😃😂😂😂源码地址
本文完。