Mockjs在前端H5中的实践

Mockjs

Mock.js 是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试。提供了以下模拟功能:
• 根据数据模板生成模拟数据
• 模拟 Ajax 请求,生成并返回模拟数据
• 基于 HTML 模板生成模拟数据
详细请查看文档

安装和使用

Node(CommonJS)

// 安装
npm install mockjs

// 使用
var Mock = require('mockjs');
var data = Mock.mock({
  'list|1-10': [{
    'id|+1': 1
  }]
});
console.log(JSON.stringify(data, null, 2))

Bower

npm install -g bower
bower install --save mockjs

<script type="text/javascript" src="./bower_components/mockjs/dist/mock.js"></script>

语法规范

Mock.js 的语法规范包括两部分:
数据模板定义(Data Temaplte Definition,DTD)
数据占位符定义(Data Placeholder Definition,DPD)
更多内容请查看文档

数据模板定义 DTD

数据模板中的每个属性由 3 部分构成:属性名、生成规则、属性值

// 属性名   name
// 生成规则 rule
// 属性值   value
'name|rule': value

注意:
● 属性名 和 生成规则 之间用 | 分隔。
● 生成规则 是可选的。
● 生成规则 有 7 种格式:
a. 'name|min-max': value
b. 'name|count': value
c. 'name|min-max.dmin-dmax': value
d. 'name|min-max.dcount': value
e. 'name|count.dmin-dmax': value
f. 'name|count.dcount': value
g. 'name|+step': value
● 生成规则 的 含义 需要依赖 属性值 才能确定。
● 属性值 中可以含有 @占位符。
● 属性值 还指定了最终值的初始值和类型。
生成规则和示例:

  1. 属性值是字符串 String
    a. 'name|min-max': 'value' 通过重复 'value' 生成一个字符串,重复次数大于等于 min,小于等于 max。
    b. 'name|count': 'value' 通过重复 'value' 生成一个字符串,重复次数等于 count。
  2. 属性值是数字 Number
    a. 'name|+1': 100 属性值自动加 1,初始值为 100
    b. 'name|1-100': 100 生成一个大于等于 1、小于等于 100 的整数,属性值 100 只用来确定类型。
    c. 'name|1-100.1-10': 100 生成一个浮点数,整数部分大于等于 1、小于等于 100,小数部分保留 1 到 10 位。 { 'number1|1-100.1-10': 1, 'number2|123.1-10': 1, 'number3|123.3': 1, 'number4|123.10': 1.123 } // => { "number1": 12.92, "number2": 123.51, "number3": 123.777, "number4": 123.1231091814 }
  3. 属性值是布尔型 Boolean
    a. 'name|1': value 随机生成一个布尔值,值为 true 的概率是 1/2,值为 false 的概率是 1/2。
    b. 'name|min-max': value 随机生成一个布尔值,值为 value 的概率是 min / (min + max),值为 !value 的概率是 max / (min + max)。
  4. 属性值是对象 Object
    a. 'name|min-max': {} 从属性值 {} 中随机选取 min 到 max 个属性。
    b. 'name|count': {} 从属性值 {} 中随机选取 count 个属性。
  5. 属性值是数组 Array
    a. 'name|1': [{}, {} ...] 从属性值 [{}, {} ...] 中随机选取 1 个元素,作为最终值。
    b. 'name|min-max': [{}, {} ...] 通过重复属性值 [{}, {} ...] 生成一个新数组,重复次数大于等于 min,小于等于 max。
    c. 'name|count': [{}, {} ...] 通过重复属性值 [{}, {} ...] 生成一个新数组,重复次数为 count。
  6. 属性值是数组 Function'name': function(){} 执行函数 function(){},取其返回值作为最终的属性值,上下文为 'name' 所在的对象。

Express + Mockjs 自建mock平台

若对Express或者Koa陌生,可参考express和koa对比。若觉得自建mock平台比较耗费资源,可以使用三方mock平台。

// node index.js启动后,在浏览器访http://localhost:3000/mockStudentList即可看到模拟数据。
const express = require("express");
const app = express();
const Mock = require("mockjs");

app.get("/mockStudentList", function (req, res) {
  const data = Mock.mock({
    "list|10-20": [
      {
        "id|+1": 1,
        "name|1": "@cname",
        "age|1-120": 18,
        "rate|1-5": "※",
        "score|1-100.2": 60,
        "isStudent|1-9": true,
        "skill|1-5": {
          read: "good",
          say: "good",
          write: "good",
          listen: "good",
          execute: "good",
        },
        "special|1": ["read", "say", "write", "listen", "execute"],
      },
    ],
  });
  res.send(data);
});

app.listen(3000, () => {
  console.log("start service success on port 3000");
});

Anymock三方mock平台

Anymock 是新一代数据接口平台。
1.标准化接入;
2.数据可编程;
3.代码无侵入
理解并掌握mockjs的语法之后,根据官方文档及能进行接口设计和数据配置,详细请参考文档。建议使用三方mock数据平台,免去自己搭建成本和服务器资源。当然,有时间可以了解自建方案。

Anymock在React项目中实践

在react项目中,通过修改package.json配置代理。但是只能进行简单配置,若配置多个或者配置更多选项,则在编译项目时抛出错误。

"proxy": "https://target.com/xxxService/apiXXX"

使用http-proxy-middleware进行代理配置

http-proxy-middleware 工作示意图

安装

npm i -D http-proxy-middleware

配置

在工程src目录下新增setupProxy.js文件并复制以下内容保存,启动项目后,会在本地启动一个代理服务(默认由exporess实现)并监听3000端口,接口地址如'localhost:3000/api/xxx'将被代理为https://anymock.alipay.com/direct-mock/http/${mockToken}/api/xxx

const { createProxyMiddleware } = require('http-proxy-middleware');
const debug = true;
const mockToken = '****'; // anymock平台的token
const onOpen = (proxySocket) => {
  console.log('on proxy open');
  console.log('proxySocket: ', proxySocket);
};
const onClose = (proxyRes, proxySocket, proxyHead) => {
  console.log('on proxy close');
  console.log('proxyRes: ', proxyRes);
  console.log('proxySocket: ', proxySocket);
  console.log('proxyHead: ', proxyHead);
};
const onError = (err, req, res, target) => {
  console.log('on proxy error');
  console.log('err: ', err);
  console.log('req: ', req);
  console.log('res: ', res);
  console.log('target: ', target);
};
const onProxyRes = (proxyRes, req, res) => {
  console.log('on proxy response');
  console.log('proxyRes: ', proxyRes);
  console.log('req: ', req);
  console.log('res: ', res);
};
const onProxyReq = (proxyReq, req, res, options) => {
  console.log('on proxy request');
  console.log('proxyReq: ', proxyReq);
  console.log('req: ', req);
  console.log('res: ', res);
  console.log('options: ', options);
};
const onProxyReqWs = (proxyReq, req, socket, options, head) => {
  console.log('on proxy request ws');
  console.log('proxyReq: ', proxyReq);
  console.log('req: ', req);
  console.log('socket: ', socket);
  console.log('options: ', options);
  console.log('head: ', head);
};
const callbacks = debug ? { onError, onProxyRes, onProxyReq, onProxyReqWs, onOpen, onClose } : {};
module.exports = function (app) {
  app.use(
    '/api',
    createProxyMiddleware({
      logLevel: 'debug',
      target: `https://anymock.alipay.com/direct-mock/http/${mockToken}/api`,
      ws: true,
      secure: false,
      changeOrigin: true,
      pathRewrite: {
        '^/api/drug/articleService': '/',
      },
      ...callbacks,
    })

模拟实现

/*
 express + http-proxy-middleware 代理请求
 */
const express = require("express");
const timeout = require("connect-timeout");
const proxy = require("http-proxy-middleware");
const app = express();
// 本服务端口
const PORT = 9527;
// cookie写入地址
const cookieUrl = "127.0.0.1";
// anymock 平台token
const mockToken = "****";
// PORT 服务端口
const mockServiceOption = {
  target: `https://anymock.alipay.com/direct-mock/http/${mockToken}/api`,
  changeOrigin: true,
  cookieDomainRewrite: {
    "*": cookieUrl, // 把相应的 cookie 域都设置成 localhost
  },
  ws: true,
  withCredentials: true,
};

// 超时时间
const TIME_OUT = 30 * 1e3;

// 设置超时 返回超时响应
app.use(timeout(TIME_OUT));
//设置跨域访问
app.all("*", function (req, res, next) {
  res.header("Access-Control-Allow-Origin", req.headers.origin);
  res.header(
    "Access-Control-Allow-Headers",
    "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Access-Control-Allow-Headers,Authorization,Origin,Accept,Power-By,x-token-id"
  );
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  res.header("Access-Control-Allow-Credentials", true);
  res.header("accept", "image/webp,image/png,image/*,*/*;q=0.8");
  next();
});
app.use((req, res, next) => {
  if (!req.timedout) next();
});
// mock服务代理
app.use(proxy("/api", { ...mockServiceOption }));

// 监听端口
app.listen(PORT, () => {
  console.log( `启动代理服务器 => http://127.0.0.1: ${PORT}`);
});

在Anymock平台创建接口

如上配置,在anymock平台上,创建项目,并在项目底下创建'api/xxx'接口,定义返回数据即可。


anymock平台编辑mock接口

至此,启动项目后,即可获得在anymock平台配置的模拟数据。

Anymock在Vue项目中实践

在vue项目中使用非常简单,按照正常的代理配置即可。
修改vue.config.js 添加以下配置重启项目即可。

devServer: {
  proxy: {
    '/api': {
      target: `https://anymock.alipay.com/direct-mock/http/${mockToken}/api`,  
      ws: true,        //如果要代理 websockets,配置这个参数
      secure: false,  // 如果是https接口,需要配置这个参数
      changeOrigin: true,  //是否跨域
      pathRewrite:{
        '^/api':''
      }
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 一、了解mockjs 前言:mockjs是什么 生成随机数据,拦截 Ajax 请求。 通过随机数据,模拟各种场景;...
    xikoo0阅读 825评论 0 3
  • 一、为什么使用mockjs 在做开发时,当后端的接口还未完成,前端为了不影响工作效率,手动模拟后端接口 二、moc...
    努力的莹莹阅读 2,645评论 0 2
  • 官网https://github.com/nuysoft/Mock/wiki/Getting-Started 一、...
    Maco_wang阅读 71,560评论 2 35
  • 前端开发过程中免不了出现等接口的情况,而静态 JSON 不足以体现前端高大上的逼格,是时候拿出 mock.js 了...
    MrWelson阅读 1,763评论 0 0
  • Mock.js语法规范包括两部分:数据模板定义规范和数据占位符定义规范。 1.数据模板定义规范: 数据模板中的每个...
    汶沐阅读 483评论 0 1