在开发过程中,前后端不论是否分离,接口多半是滞后于页面开发的。所以建立一个REST风格的API接口,给前端页面提供虚拟的数据,是非常有必要的。
对比过多种mock工具后,我最终选择了使用 json server
作为工具,因为它足够简单,写少量数据,即可使用。
也因为它足够强大,支持CORS和JSONP跨域请求,支持GET, POST, PUT, PATCH 和 DELETE 方法,更提供了一系列的查询方法,如limit,order等。下面我将详细介绍 json server
的使用。
首先你的电脑中需要安装nodejs,建议使用最新版本。然后全局安装json server.
npm install json-server -g
使用linux和macOS的电脑需要加上sudo
sudo npm install json-server -g
安装完成后可以用 json-server -h
命令检查是否安装成功,成功后会出现
json-server [options] <source>
选项:
--config, -c Path to config file [默认值: "json-server.json"]
--port, -p Set port [默认值: 3000]
--host, -H Set host [默认值: "0.0.0.0"]
--watch, -w Watch file(s) [布尔]
--routes, -r Path to routes file
--static, -s Set static files directory --read-only, --ro Allow only GET requests [布尔] --no-cors, --nc Disable Cross-Origin Resource Sharing [布尔] --no-gzip, --ng Disable GZIP Content-Encoding [布尔] --snapshots, -S Set snapshots directory [默认值: "."] --delay, -d Add delay to responses (ms) --id, -i Set database id property (e.g. _id) [默认值: "id"] --quiet, -q Suppress log messages from output [布尔] --help, -h 显示帮助信息 [布尔] --version, -v 显示版本号 [布尔] 示例: json-server db.json json-server file.js json-server http://example.com/db.json https://github.com/typicode/json-server
安装完成后,可以在任一目录下建立一个 xxx.json
文件,例如在 mock/
文件夹下,建立一个 db.json
文件,并写入以下内容,并在 mock/
文件夹下执行 json-server db.json -p 3003
。
{
"news":[
{
"id": 1, "title": "曹县宣布昨日晚间登日成功", "date": "2016-08-12", "likes": 55, "views": 100086 }, { "id": 2, "title": "长江流域首次发现海豚", "date": "2016-08-12", "likes": 505, "views": 9800 } ], "comments":[ { "id": 1, "news_id": 1, "data": [ { "id": 1, "content": "支持党中央决定" }, { "id": 2, "content": "抄写党章势在必行!" } ] } ] }
为了方便,再创建一个 package.json
文件,写入
{
"scripts": {
"mock": "json-server db.json --port 3003" } }
然后使用到 /mock
目录下执行 npm run mock
命令,如果成功会出现
> @ mock /你的电脑中mock文件夹所在目录的路径/mock
> json-server db.json -p 3003
\{^_^}/ hi!
Loading db.json
Done
Resources
http://localhost:3003/news
http://localhost:3003/comments
Home
http://localhost:3003
如果不成功请检查 db.json
文件的格式是否正确。
这个时候访问 http://localhost:3003/db
可以查看 db.json
文件中所定义的全部数据。
使用浏览器地址栏,jQuery.get
或 fecth({method: "get"})
访问 http://localhost:3003/news
,则可以看到 news
对象下的数据,以Array格式返回:
[
{
"id": 1,
"title": "曹县宣布昨日晚间登日成功", "date": "2016-08-12", "likes": 55, "views": 100086 }, { "id": 2, "title": "长江流域首次发现海豚", "date": "2016-08-12", "likes": 505, "views": 9800 } ]
以jquery的 $.ajax
方法举例,以下代码会实时的向 db.json
中的 news
对象push一条新的数据再次用 get
方式访问 http://localhost:3003/news
, 就可以看到它了
$.ajax({
type: 'post', url: 'http://localhost:3003/news', data: { "id": 3, "title": "我是新加入的新闻", "date": "2016-08-12", "likes": 0, "views": 0 } } )
同样以jquery的 $.ajax
方法举例,以下代码会实时的对 db.json
中的 news
对象中 id=1
数据进行修改
$.ajax({
type: 'put',
url: 'http://localhost:3003/news/1',
data: {
"title": "曹县宣布昨日晚间登日失败", "date": "2016-08-12", "likes": 55, "views": 100086 } } ) // 结果 [ { "id": 1, "title": "曹县宣布昨日晚间登日失败", "date": "2016-08-12", "likes": 55, "views": 100086 } ]
PATCH 和 DELETE 使用方式同上,就不做演示了。
json-server源码 : json-server
mockjs源码 : mockjs
demo : 示例代码
https://segmentfault.com/a/1190000005793320
上一篇演示时,使用了 db.json
作为数据载体,虽然方便,但是如果需要大量的数据,则显得力不从心。
幸好 json server
可以通过js动态生成json格式数据,官方例子为生成1000组user数据:
# /mock/db.js
module.exports = function() { var data = { users: [] } // Create 1000 users for (var i = 0; i < 1000; i++) { data.users.push({ id: i, name: 'user' + i }) } return data }
/mock
下运行
json-server db.js -p 3003
我们访问 http://localhost:3003/news/
看到的数据是
[
{"id": 0,"name": "user0"}, {"id": 1,"name": "user1"}, {"id": 2,"name": "user2"}, {"id": 3,"name": "user3"}, ... {"id": 999,"name": "user999"} ]
但是在开发环境中,name
这个属性应该是诸如 “李铁蛋”, “张艳华” 或者是 “Brenda Thomas”,
“Daniel Wilson” 这样接地气的名字,而不是 “user0”, “user1” 这样让人望而生畏的名字,对于用户的
年龄,性别,籍贯,也应该有比较合理的数据展示。
数据生成器有很多,比较出名的有 faker ,chance ,mockjs 等,其中最为强大的非 faker 莫属,不但拥有几乎全部常用的数据格式,而且还有中英德法等多种语言的数据。但是在实际测试中发现,faker 对中文数据的支持还是以西方文字为基础,并不能很好的模拟中文,例如:
let faker = require('faker');
faker.locale = "zh_CN"; console.log(faker.address.city()); => 南 罗 console.log(faker.address.streetName()); => 陈 桥 console.log(faker.company.companyName()); => 静琪 - 越泽 console.log(faker.date.month()); => May console.log(faker.internet.email()); => 87@yahoo.com console.log(faker.phone.phoneNumber()); => 922-61957652
这些看起来有些怪异的中文格式,多半是不能用于国内的数据模拟的,我们再看看 mockjs 的表现:
let Mock = require('mockjs');
let Random = Mock.Random; console.log(Random.city()); => 珠海市 console.log(Random.cname()); => 韩桂英 console.log(Random.date()); => 2007-08-05 console.log(Mock.mock({ => {stars: '★★★★★'} "stars|1-10": "★" })); Random.image('200x100', '#4A7BF7', 'hello') => 见下图
虽然 mockj s可以模拟的数据不如 faker 那么多,但是由于其对中文的良好支持,并且使用了位于国内的随机图片提供商,显然是更适合国情的选择。
请先用15分钟阅读 mockjs官方文档
在 /mock
目录下安装
npm install mockjs --save
我知道有些人不会去认真的阅读官方文档,所以在此摘抄一些官方文档中的例子作为示范:
// repeat 方法(部分)
Mock.mock({
"string|5": "★" => "string": "★★★★★" "string|1-10": "★" => "string": "★★" "number|1-100": 100 => "number": 85 "number|1-100.2": 100 => "number": 25.69 })
我知道有些人不会去认真的阅读官方文档,所以在此摘抄一些官方文档中的例子作为示范:
// random 方法(部分)
Random.integer(60, 100) => 78 Random.float(60, 100) => 89.565475 Random.range(60, 100) => [60,61,62,...,99] Random.date() => "2018-12-28" Random.image('200x100','#396') => "http://dummyimage.com/200x100/396" Random.color() => "#79d8f2" (默认使用hex颜色) Random.county(true) => "浙江省 舟山市 岱山县"
通过阅读 mockjs 的官方文档可以发现,它其实是作为一个独立的 mock server 存在的,就算没有json server,一样可以反馈数据,但是由于以下一些缺点,让我只能把它作为一个数据构造器来使用:
不能跨域使用
与某些框架中的路由处理逻辑冲突
无法定义复杂的数据结构,比如下面的数据结构,images 将会是字符串 [object object]
, 而非预想中的数组:
Mock.mock({
"list|1-10": [
"id|+1": 1,
"images": [1,2,3] ] })
无法自定义较为复杂的路由
下面是一个使用 mockjs 构造的比较复杂的数据格式,对象是一个新闻列表,其中有100条新闻,每条新闻有对应的id,标题,内容,简介,标签,浏览量,和一个图片数组:
# /mock/db.js
let Mock = require('mockjs');
let Random = Mock.Random; module.exports = function() { var data = { news: [] }; var images = [1,2,3].map(x=>Random.image('200x100', Random.color(), Random.word(2,6))); for (var i = 0; i < 100; i++) { var content = Random.cparagraph(0,10); data.news.push({ id: i, title: Random.cword(8,20), desc: content.substr(0,40), tag: Random.cword(2,6), views: Random.integer(100,5000), images: images.slice(0,Random.integer(1,3)) }) } return data }
/mock
下运行
json-server db.js -p 3003
访问 http://localhost:3003/news
看到的数据是:
[
{
"id": 0,
"title": "元小总小把清保住影办历战资和总由", "desc": "共先定制向向圆适者定书她规置斗平相。要广确但教金更前三响角面等以白。眼查何参提适", "tag": "值集空", "views": 3810, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置", "http://dummyimage.com/200x100/f28279&text=收面几容受取", "http://dummyimage.com/200x100/7993f2&text=做件" ] }, { "id": 1, "title": "物器许条对越复术", "desc": "方江周是府整头书生权部部条。始克识史但给又约同段十子按者感律备。关长厂平难山从合", "tag": "分七眼术保", "views": 4673, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置" ] }, { "id": 2, "title": "但学却连质法计性想般最", "desc": "以群亲它天即资几行位具回同务度。场养验快但部光天火金时内我。任提教毛办结论感看还", "tag": "响六", "views": 4131, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置", "http://dummyimage.com/200x100/f28279&text=收面几容受取", "http://dummyimage.com/200x100/7993f2&text=做件" ] }, ... { "id": 99, "title": "则群起然线部其深我位价业红候院", "desc": "为高值务须西生型住断况里听。志置开用她你然始查她响元还。照员给门次府此据它后支越", "tag": "何你", "views": 2952, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置" ] } ]
json-server源码 : json-server
mockjs源码 : mockjs
demo : 示例代码
https://segmentfault.com/a/1190000005793520
在安装好json server之后,通过 json-server -h
可以看到如下配置项:
json-server [options] <source>
Options:
--config, -c 指定 config 文件 [默认: "json-server.json"]
--port, -p 设置端口号 [default: 3000] --host, -H 设置主机 [默认: "0.0.0.0"] --watch, -w 监控文件 [boolean] --routes, -r 指定路由文件 --static, -s 设置静态文件 --read-only, --ro 只允许 GET 请求 [boolean] --no-cors, --nc 禁止跨域资源共享 [boolean] --no-gzip, --ng 禁止GZIP [boolean] --snapshots, -S 设置快照目录 [默认: "."] --delay, -d 设置反馈延时 (ms) --id, -i 设置数据的id属性 (e.g. _id) [默认: "id"] --quiet, -q 不输出日志信息 [boolean] --help, -h 显示帮助信息 [boolean] --version, -v 显示版本号 [boolean] Examples: bin db.json bin file.js bin http://example.com/db.json
既可以通过命令行方式单行配置,如
json-server db.js -p 3003 -d 500 -q -r ./routes.json
,也可以通过 json-server.json
文件进行配置后:
# /mock/json-server.json
{
"host": "0.0.0.0",
"port": "3003", "watch": false, "delay": 500, "quiet": true, "routes": "./routes.json" }
运行
json-server db.js
在 /mock
下建立 public
目录,即可直接访问其下的所有静态文件,包括但不限于
js
, css
,markdown
文件等。
地址栏输入 http://localhist:3003/readme.md
即可访问以下文件
# /mock/public/readme.md
# hello Mr DJ,这节奏不要停
通过 json server
建立的rest api服务默认可以在局域网中通过WIFI访问接口。
windows下面通过 ipconfig
查找到电脑的局域网地址.mac设备是通过 ifconfig | grep "inet " | grep -v 127.0.0.1
查看。
比如我的电脑局域网ip是 192.168.0.6
,在手机上访问 http://192.168.0.6:3003
即可。
可以通过自定义路由的形式,简化数据结构,或是建立高弹性的web api,例如
# /mock/routes.json
{
"/news/:id/show": "/news/:id",
"/topics/:id/show": "/news/:id", }
访问 /news/1/show
和 topics/1/show
均返回指定的 /news/1
内容。
* 需要注意的是,路由必须以 /
开头
相比在终端中直接输入各种命令,我更喜欢利用 node scripts
来处理任务,在 /mock
下建立文件 package.json
,然后运行 npm run mock
。
# /mock/package.json
{
"scripts": {
"mock": "json-server db.js" } }
数据过滤是 json server
中非常强力的功能。通过url上简单的query字段,即可过滤出各种各样的数据。
示例数据源:
[
{
"id": 0,
"title": "元小总小把清保住影办历战资和总由", "desc": "共先定制向向圆适者定书她规置斗平相。要广确但教金更前三响角面等以白。眼查何参提适", "tag": "值集空", "views": 3810, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置", "http://dummyimage.com/200x100/f28279&text=收面几容受取", "http://dummyimage.com/200x100/7993f2&text=做件" ] }, { "id": 1, "title": "物器许条对越复术", "desc": "方江周是府整头书生权部部条。始克识史但给又约同段十子按者感律备。关长厂平难山从合", "tag": "分七眼术保", "views": 4673, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置" ] }, { "id": 2, "title": "但学却连质法计性想般最", "desc": "以群亲它天即资几行位具回同务度。场养验快但部光天火金时内我。任提教毛办结论感看还", "tag": "响六", "views": 4131, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置", "http://dummyimage.com/200x100/f28279&text=收面几容受取", "http://dummyimage.com/200x100/7993f2&text=做件" ] }, ... { "id": 99, "title": "则群起然线部其深我位价业红候院", "desc": "为高值务须西生型住断况里听。志置开用她你然始查她响元还。照员给门次府此据它后支越", "tag": "何你", "views": 2952, "images": [ "http://dummyimage.com/200x100/79f2a5&text=别角置" ] } ]
使用 .
操作对象属性值
// 获取图片数量为3,且标签字数为2的新闻
GET /news?images.length=3&tag.length=2
使用 _start
和 _end
或者 _limit
(response中会包含 X-Total-Count
)
// 获取id=10开始的5篇新闻
GET /news?_start=10&_limit=5
// 获取id=20开始,id=35结束的新闻 GET /news?_start=20&_end=35
使用 _sort
和 _order
(默认使用升序(ASC))
// 按照浏览数量降序排列
GET /news?_sort=views&_order=DESC
使用 _gte
或 _lte
选取一个范围
// 选取浏览量在2000-2500之间的新闻
GET /news?views_gte=2000&views_lte=2500
使用 _ne
排除一个值
// 选择tag属性不是 "国际新闻" 的分类
GET /news?tag_ne=国际新闻
使用 _like
进行模糊查找 (支持正则表达式)
// 查找title中含有 "前端" 字样的新闻
GET /news?title_like=前端
使用 q
,在对象全部value中遍历查找包含指定值的数据
// 查找新闻全部字段包含 "强拆" 字样的数据
GET /news?q=强拆
获取包含下级资源的数据, 使用 _embed
GET /news?_embed=comments
GET /news/1?_embed=comments
获取包含上级资源的数据, 使用 _expand
GET /news?_expand=post
GET /news/1?_expand=post
除了独立作为rest api 服务器之外, json server
同样可以作为诸如 Express
之类框架的中间件使用,具体API详见 json server模块
json-server源码 : json-server
mockjs源码 : mockjs
demo : 示例代码