简单的基于 koa 的 mock 数据服务器
npm i -g @ybq/mockr
npm run mockr
mockr 会在当前目录(执行命令的目录)下寻找名为 mockr-config.js
的配置文件
一下是一个配置的示例
module.exports = {
restfulURLs: [
['/a', null, '/b', null],
],
pageEntries: [
{
url: url => ['', '/', '/index'].includes(url),
template: 'index.ftl',
syncDataPath: 'index-data',
},
{
url: '/tanks/shining.do',
template: 'pages/tanks/shining.ftl',
},
{
url: '/page',
template: '/aa/bb/cc.ftl',
syncDataPath: 'pageASpecial',
},
{
url: ctx => ctx.url.includes('pageEntry'),
template: 'page/entry2.ftl',
},
{
url: /^\/regexp\/page/,
template: '/page/entry3.html',
},
],
noTemplateEngine: true,
templateRoots: ['./template'],
syncDataRoot: 'sync',
controllerRoot: 'controller',
specialControllers: [
{
url: /^\/ax\//,
path: './xxx/special.js',
},
{
url: url => url.includes('love'),
path: './love/a.js',
},
],
static: [
'.',
],
async beforeController(ctx, next) {
console.info('before');
ctx.response.set('Access-Control-Allow-Origin', '*');
ctx.response.set('Access-Control-Allow-Methods', 'GET, POST, DELETE');
if (ctx.request.path === '/foo' && ctx.request.method === 'DELETE') {
ctx.body = { retCode: 200 };
} else {
await next();
}
},
async afterController(ctx, next) {
console.info('this is after handler');
await next();
},
};
mockr的核心概念是请求匹配. mockr只是对koa做了一层简单的包装, 当请求到来时, mockr 会结合请求的path和配置的映射规则, 找到controller或数据文件的位置.
如果没有特殊指明, mockr 对所有的请求使用默认的匹配规则: 当一个请求到达时, mockr 将在 controller 路径(由配置文件中配置的根 controllerRoot
和请求的 path 拼接而成)寻找并执行 controller.
例如有如下请求: https://3000/a/b/c
, 配置文件中的 controllerRoot
配置为 controllers
. mockr 中 controller 的拼装逻辑如下
let controllerPath = path.resolve(cwd, controllerRoot, '.', ctx.request.path)
cwd 是配置文件所在的文件夹, 如果 cwd 是/Usr/xxx
, 则最终的 controller 路径为 /Usr/xxx/controllers/a/b/c
. 此时, mockr 将尝试从这个路径 require controller 文件. 如果 require 得到的是一个函数, mockr 将执行该函数, 否则执行下面的逻辑:
ctx.body = mock(requireResult)
所以你可以在 /Usr/xxx/controllers/a/b/
路径添加一个 c.js
或 c.json
作为 controller
如果请求 URL 中包含参数, 例如如下形式:
/name/${name}/age/${age}
真实的 URL 如下:
/name/Tom/age/12
可以在配置文件的 restfulURLs
中指定 restful URL 的模板, restfulURLs
的值是一个数组, 数组中每个元素代表一种 URL 模板. 在上面例子中, 配置为如下格式:
restfulURLs: [
['/name', null, '/age', null],
// 其他模板
]
如果以上的规则不能满足你的需求, 你也可以定制自己的 controller 映射规则. 编辑配置文件中的 specialControllers
, 此配置项的值是一个数组, 数组中的每一项是包含两个属性(url
, path
)的对象, url
属性可以是正则表达式, 函数或字符串. path
是 controller 相对 controllerRoot
的路径. 如果 url
是正则表达式, mockr 会执行正则匹配 url.test(${requestURL})
; 如果 url
是函数, mockr 会将请求的上下文 ctx 传入 url
函数获取匹配结果, 否则 mockr 直接比较 url
是否等于请求的 URL, 即如下:
let matched = url === ${requestURL}
如果执行结果为 true, mockr 将执行此元素 path 属性指定的 controller
- Freemarker
Mockr 支持对 freemarker 模板的渲染. 进行页面渲染需要在配置文件中配置
pageEntries
,templateRoots
,syncDataRoot
和static
templateRoots
是字符串数组, 每个元素代表一个文件夹, 文件夹内放置模板文件. 通常情况你只需要设置一个就够了.
pageEntries
也是一个数组, 数组中每个元素时包含两个或三个属性(url
, template
, syncDataPath
)的对象(syncDataPath
可省略). url
同上面特殊规则提到的 url 一样, template
是请求对应的模板文件路径, syndDataPath
类似于 controller, 它提供用于渲染页面的同步数据.
获取一个请求的同步数据时, Mockr 将 syncDataRoot
和 syncDataPath
合并, 得到一个路径, 然后使用和 controller 相同的逻辑, 得到同步数据, 塞到模板中进行渲染
- HTML
mockr也支持不使用模板引擎, 直接取html文件输出到前端. 配置
noTempalteEngine: true
. 当请求到来时, mockr根据规则寻找到html文件输出到前端
请求到来是, mockr 先遍历检查 pageEntries
规则, 查看请求是否是一个页面请求. 如果是页面请求, 并且配置了 syndDataPath
, mockr 将 require 数据文件并渲染页面. 如果 syncDataPath
没配置, mockr 将使用默认规则获取同步数据并进行渲染.
如果请求不是页面请求(例如 ajax 请求), mockr 会通过特殊规则寻找 controller. 如果找到了, 直接执行 controller.
如果通过特殊规则没有找到 controller, mockr 将遍历 restfulURLs
查看请求的 url 是否匹配数组中的元素. 如果匹配, 则按照 restful 规则组装 controller 路径寻找 controller 并执行, 规则如下:
将请求 URL 中的参数对应的位置替换成 _param
, 例如:
/name/Top/age/12
替换后的 controller 路径为 /name/_param/age/_param
.
如果仍然没有找到 controller, mockr 将根据默认规则寻找 controller
static
配置项用于设置前端资源(css/js/img/font)的路径. mockr内部使用koa-static
来处理前端资源请求
-
controller 文件的变动是即时生效的, 修改 controller 文件不需要重启 mockr. (如果修改的是被controller文件引用的文件或配置文件, 则需要重启mockr)
-
可以在 controller 前后设置 beforeController 和 afterController 来达到在 controller 前后插入逻辑的目的, 例如设置跨域允许等.
等多配置细节, 见 test
ISC