www.2527.com_澳门新葡8455手机版_新京葡娱乐场网址_
做最好的网站

浅谈前端mock,0中集成MockApi的不二等秘书诀自己

2020-02-02 01:01 来源:未知

时间: 2019-02-23阅读: 904标签: mock引言

一、为什么要模拟数据?

项目开发中,前端工程师需要依赖后端工程师的数据接口以及后端联调环境。但是其实我们也可以根据后端接口文档在接口没有开发完成之前自己mock数据进行调试,让接口消费者脱离接口生产者进行开发。

一:使用场景

前端开发经常需要等待后端的接口,严重影响了开发效率,我们一般采用mock方式来避免这个问题。本人参考了大量文章,结合自己的经验,给出自己在mock上的一些理解。由于作者刚参加工作,水平有限,如果哪里写到不对,请评论指出。

二、Mock数据常见的解决方案有什么?

在 server 端 mock

在 client 端 mock

  1. 在代码层硬编码

    在负责请求接口的函数里,直接定义一个数据变量,该变量保存了回返的 Mock数据。

    这种Mock方法操作比较简单,但缺点也很明显,就是Mock 更改了代码逻辑,和代码耦合性太强。而且并不能模拟真实的网络请求的过程。

  1. 在前端JS中拦截

    典型的解决方案就是Mock.js,通过在业务代码前挂载该JS文件,拦截Ajax请求。这种Mock方式相较于硬编码,虽然实现了Mock 与代码的部分解耦,但无法完全和业务代码解耦(因为必须挂载一个JS并进行 Mock配置)。

    虽然提供了大量的Mock API,但是也仍然无法发出真实的网络请求,模拟真实度不够。另外这种方式还存在一些不足,因为是对XHR对象的改写,有些情况下兼容性并不好,比如IE8等低版本浏览器,还有较新的Fetch API也拦截不到。

  1. 代理软件(Fiddler、Charles抓包)

    Fiddler和Charles可以对网络请求进行拦截将其替换为我们需要的Mock 数据,这也不失为一种Mock方式。其优点主要是真实性强,但这种方式操作步骤比较繁琐,不方便统一配置,Mock成本较高。

  1. Mock-Server

    最合适的方案无外乎搭建独立的 Mock-Server,开发的前期阶段,所有的接口都会指向该 Mock-Server。因为可能存在跨域的情况,所以一般都需要在开发环境搭配一套接口代理做搭配。这种方案对业务代码完全不具有侵入性,并且通用性强。

    缺点也很明显,成本高(还需要另起一个Mock-Server服务,并对其进行管理)。

  1. RAP

    ......

哎哟,好烦啊,这个需求还么结束就来下一个需求,程序员不要排期的吗?

  1. 原理

三、Mock数据实例

1. MockJS

数据生成器有很多,比较出名的有faker、chance、mockjs等,其中最为强大的非faker莫属,不但拥有几乎全部常用的数据格式,而且还有中英德法等多种语言的数据。但是在实际测试中发现,faker对中文数据的支持还是以西方文字为基础,并不能很好的模拟中文。并且mockjs使用了位于国内的随机图片提供商。

原理:Mock.js 通过覆盖和模拟原生 XMLHttpRequest 的行为来拦截 Ajax 请求“转发”到本地文件,所谓转发,其实就是读取本地 mock文件,并以json或者script等格式返回给浏览器(还需要补充)。

mockjs能做的事情是拦截Ajax请求,可以返回各种随机的数据。

Webpack dev.config.js:

plugins:[
    new webpack.DefinePlugin({
        MOCK: true
    })
]

DefinePlugin插件允许创建一个在编译时可以配置的全局变量,
使用功能标记来「启用/禁用」「生产/开发」构建中的功能。

入口文件:

if (MOCK) {
    require('mock/mock');
}

Project mock/mock.js:

import Mock from 'mockjs';
Mock.mock('/api/user', {
    'name': '@cname',
    'intro': '@word(20)'
});

Mock.js的语法规范:

根据数据模板生成模拟数据

Mock.mock( rurl?, rtype?, template|function( options ) )

  • 数据模板定义规范

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

    'name|rule': value

    'name|min-max': value

    'name|count': value

    'name|min-max.dmin-dmax': value

    'name|min-max.dcount': value

    'name|count.dmin-dmax': value

    'name|count.dcount': value

    'name| step': value

  • 数据占位符定义规范 @

示例:

'list|1-10': [{
    'order_id| 1': 1,
    'user_id|100-200': 1,
    'is_deposit|1': true,
    'city|2-4': {
        "110000": "北京市",
        "120000": "天津市",
        "130000": "河北省",
        "140000": "山西省"
    },
    'status|1': [
        '已注册',
        '已开户',
        '已入金',
        '已注销'
    ],
    'guid': '@guid',
    'first': '@cfirst()',
    'last': '@clast()',
    'name': '@cname',
    // 随机生成一个18位身份证
    'id': '@id',
    'title': '@ctitle(3,10)',
    'paragraph': '@cparagraph(2,5)',
    'image': "@image('200x100', '#4A7BF7', 'img', 'png', 'Tiger')",
    // 随机生成一个6位的邮编
    'zip': '@zip()',
    // 随机生成一个中国大区
    'region': '@region()',
    // 随机生成一个(中国)省(或直辖市、自治区、特别行政区
    'province': '@province()',
    // 随机生成一个(中国)市,prefix指示是否生成所属的省
    'city': '@city(true)',
    // 随机生成一个(中国)县,prefix指示是否生成所属的省、市
    'address': '@county(true)',
    'date': '@date("yyyy-MM-dd")',
    'datetime': '@datetime("yyyy-MM-dd HH:mm:ss")',
    'time': '@time("HH:mm:ss")',
    'sentence': '@csentence(2, 5)',
    'url': '@url',
    // 随机生成一个域名
    'domain': '@domain()',
    // 随机生成一个顶级域名
    'tld': '@tld()',
    // 指定邮件的地址域名
    'email': '@email("gmail.com")',
    'color': '@color()',
    'ip': '@ip',
    'regexp': /[a-z][A-Z][0-9]/,
}]

我们希望mock该有的能力:

  • 与线上环境一致的接口地址,每次构建前端代码时不需要修改调用接口的代码

  • 所改即所得,具有热更新的能力,每次增加/修改mock 接口时不需要重启mock服务,更不用重启前端构建服务

  • 能配合构建工具

  • mock数据可以由工具生成不需要自己手动写

  • 能模拟POST、GET等请求

  • 基于数据模板生成数据

所以我们有了第二种方案:

2. json-server

  • mockjs nodemon

json-server主要是搭建一台json服务器,支持CORS和JSONP跨域请求。支持 GET、POST、PUT、PATCH和DELETE方法,更提供了一系列的查询方法,如 limit、order等。

CLI usage

➜ json-server -h
json-server [options] <source>

选项:
  --config, -c               指定config文件 [默认值: "json-server.json"]
  --port, -p                 设置端口号 [默认值: 3000]
  --host, -H                 设置主机 [默认值: "0.0.0.0"]
  --watch, -w                监控文件 [布尔]
  --routes, -r               指定路由文件
  --middlewares, -m          ---- [数组]
  --static, -s               设置静态文件
  --read-only, --ro          只允许GET请求 [布尔]
  --no-cors, --nc            禁止跨域资源共享 [布尔]
  --no-gzip, --ng            禁止GZIP [布尔]
  --snapshots, -S            设置快照目录 [默认值: "."]
  --delay, -d                设置反馈延时(ms)
  --id, -i                   设置数据的id属性(e.g. _id) [默认值: "id"]
  --foreignKeySuffix, --fks  Set foreign key suffix (e.g. _id as in post_id)
  --quiet, -q                不输出日志信息 [布尔]
  --help, -h                 显示帮助信息 [布尔]
  --version, -v              显示版本号 [布尔]

json-server   // json-server服务
nodemon       // 修改配置无需重启服务
mockjs        // 批量生成数据

具体的实现方案:

package.json

"scripts": {
    ...
    "mockdev": "nodemon mock/server.js & npm start"
  }

目录结构

|--mock
    |--config.js  配置文件
    |--db.js      数据文件
    |--routes.js  路由映射
    |--server.js  服务文件

config.js -- 配置端口等

module.exports = {
  SERVER:"127.0.0.1",  
  //定义端口号
  PORT: 3003,
  //定义数据文件
  DB_FILE:"./db.js"
};

db.js -- 批量生产数据文件

let Mock  = require('mockjs');
let Random = Mock.Random;
module.exports = function() {
  var data = { 
      <!--实际mock的接口-->
  };
  return data;
}

server.js

const config = require('./config');
const jsonServer = require('json-server');
const rules = require('./routes');
const dbfile = require(config.DB_FILE);

const ip = config.SERVER;
const port = config.PORT;
const db_file = config.DB_FILE;
// Express server
const server = jsonServer.create();
// JSON Server router
const router = jsonServer.router(dbfile());
// 中间件
const middlewares = jsonServer.defaults();

server.use(jsonServer.bodyParser);
server.use(middlewares);
// 重写路由
server.use(jsonServer.rewriter(rules));
// 设置增加一个响应头信息“从server到前端”
server.use((req, res, next) => {
 res.header('X-Hello', 'World');
 next();
})
// 数据发送到前端之前包一层
router.render = (req, res) => {
    res.jsonp({
        code: 0,
        body: res.locals.data
    })
}

server.use(jsonServer.rewriter(rules));
server.use(router);

server.listen({
    host: ip,
    port: port,
}, function() {
    console.log(JSON.stringify(jsonServer));
    console.log(`JSON Server is running in http://${ip}:${port}`);
});

routes.js -- 路由映射

module.exports= {
    "/api/": "/",
    "/:id": "/news/:id",
    "/news/:id/show": "/news/:id",
    "/topics/:id/show": "/news/:id"
}

webpack.dev.cong.js -- 代理

devServer: {
    ...
    proxy: {
        "/api/*": "http://localhost:3003"
    }
}

没办法啊,资本主义的XX嘴脸啊

何为mock,我认为mock主要就是通过正常请求在后端接口进度落后的情况下,还能获取到和后端约定数据结构一样的模拟数据的一门技术,以避免后端接口进度滞后影响我们正常的开发。mock可能会涉及到4门技术,分别是服务端技术、随机生成特定格式数据的技术、请求转发、请求拦截。

来吧,技术评审我俩把接口格式对一把,你先开发,我这边结束了我跟上,再联调

  1. 常用手段分类2.1硬刚型将模拟数据直接写在代码里

MMP,那又增加了我的工作量啊,每次我都要自己先把数据放在一个配置文件中,引入使用,然后对接的时候还得删除无用代码,好气

优点:简单暴力缺点:改变了代码原有逻辑,且耦合度高,当后端接口完成的时候还需要再改代码。

你自己Mock接口啊,就向我们后端经常用PostMan一样模拟请求啊

2.2拦截型mockjs

Mock??我去查查看

mockjs通过改写ajax函数来实现拦截请求,同时它还能伪造各种随机数据,通过mockjs我们能很方便的实现简单的mock效果,优点:简单方便缺点:无法模拟真实的请求,不支持fetch(需要额外调用插件)

二:Mock的概念

Mock.mock('/api/news', { name: 'Jack', 'age|10-20': 10 });

1:Mock的描述

Charles、 Fiddler 、postman

Mock接口其实就是模拟真实接口提供一个在开发环境的假数据,甚至是真实数据,在开发时,经常出现接口内容不能够及时的跟进,导致开发过程中添加一些额外的工作量。接下来的例子全部围绕着Vue为主体介绍前后端提前确定好通信的JSON格式之后,我们在不依赖后端进度的同时,能提供一套好的开发体验。

利用 Charles、 Fiddler 等代理工具拦截请求优点:有真实的请求缺点:配置上优点复杂

2:Mock能解决的问题

2.3Mock Servernode/express/json-server mockjs/fakejs

减少额外工作,在没有Mock接口的时候我们模拟数据的方式很烦躁,比如list列表,需要在data中声明list,去调试内容,或者引入一个mock文件,这样做导致在联调调用接口的部分代码没有写,联调成功的时候要删除很多无用代码 ---> 通过Mock只需在联调的时候把Mock接口的地址换成真实地址即可

Mock Server简单的说就是起一个服务器,服务器提供接口产生相应的mock数据前者用来起服务,后者用来产生模拟数据。json-server是对express的一个封装,用于快速构建服务器而不用写后台代码这里重点注意一下,对于一般的项目我们可以用json-server,但是如果是在vue-cli之类生成的项目里面,实际上webpack已经帮我们起了一个服务,这是我如果我们想额外起一个json-server,就需要在vue.config.js里面配置proxy。当然我们也可以不另外起服务,就用dev-server,在webpack的devServer.before里面进行配置

import { mockList2 } from 'mock/list.js';export default { data () { return { mockList: [ { "name": 'tx', "age": 12 } ], mockList2 } }}
devServer: { // proxy: { //额外起一个服务,然后进行转发 // '/api': { // target: 'json-server服务的ip:端口号', // pathRewrite: { '/api': '' } // } // } before: function(app) { //直接用devserver这个服务 app.get('/api/news', function(req, res) { res.json({ msg: 'dev-before' }) }) } }

如果采用上述的方式去模拟数据,缺少真正缺口所具备的状态,比如删除接口,有成功和失败的区分,这个模拟就很恶心了 ----> 通过Mock,可以直接通过实在的query或者其他的操作来达到同样的目的

优点:真实,低耦合,可扩展缺点:后端参与较少

3:Mock的几种方式以及对应的优缺点

2.4 Mock 平台RAP/Easy-Mock

Mock的方式

对于小型开发团队的话,Mock Server或者mockjs完全够了,因为此时前后端沟通代价比较小。但是如果是大型开发团队呢,这时候,文档的编写,接口的变更,通知到每一个人,代价就比较大了。这也是RAP,Easy-Mock这类mock平台由来的原因。优点:接口代理,协同编辑,mock数据,智能提醒,自动生成文档缺点:你要说服后端使用它

优缺点

3 具体开发流程举例

本地Mock接口 优点:可以更加细粒度的控制mock的内容。缺点:需要增加本地的代码量,以及需要配置webapck Mock.js实现ajax拦截 优点:数据通过mock.js会更丰富。缺点:增加一些本地配置,拦截ajax 后端Controller的静态JSON 优点:接口联调不需要修改任何东西。缺点:修改Mock内容沟通成本高,跟后端扯皮 利用FastMock去模拟Mock 优点:可控内容以及实现动态Restful api。缺点:如果项目包装axios等请求库之后需要针对接口转发做不同处理

这里就假设我们用devServer.before mock.js来开发假设后端要开发两个接口 www.test/api/news/, www.test/api/price/3.1 后端开没开动我们在devServer虚拟两个接口

4:本地Mock接口

在devserver里面配置beforedevServer: { before: function(app) { app.get('www.test/api1/news', function(req, res) { //只对api1进行拦截 res.json({ mockjs产生的模拟数据 }) }) app.get('www.test/api1/price', function(req, res) { //只对api1进行拦截 res.json({ mockjs产生的模拟数据 }) }) } }

//在/src/api/index.js里面const getNews = axios.get(www.test/api1/news)const getPrice = axios.get(www.test/api1/price)export {getNews,getPrice}// 由于/api1会被before拦截从而得到mock数据,没有问题

该篇文章针对本地Mock接口进行操作,其他的方式会简要介绍并给出对应的链接,如果有需要,自行去查阅。

3.2 后端开发了部分接口,比如www.test/api/news/开发完毕

三:本地Mock周边知识

//在/src/api/index.js里面修改/api1为/apiconst getNews = axios.get(www.test/api/news) //此时这个请求不会被拦截,走真实接口,而未开发完的接口请求还是走模拟数据接口

本地Mock的思想就是利用Node express完成Restful Api。结合webpack配置项devServer同时利用Vue-cli3.0的暴露的配置利用本地express完成mock接口的添加

3.3 后端全部开发完毕

1、Node Express的相关知识点,用node express写过Restful Api的就应该知道接下来Mock怎么处理了,这里我先简要介绍一下我们需要用到的技术吧(Express的路由以及node的fs模块)

全部将/api1修改为/api,同时注释掉devserver.before

Express路由相关,具体的见文档,这里不区分请求方法,直接app.use

也可以直接用mockjs进行拦截,步骤差不多,但是更简单

const express = require;const app = express();// 这样一个简单的路由就完成了,请求到/ajax-get-info的请求就能拿到对应的JSON数据app.use('/ajax-get-info',  => { res.send({ "success": true, "code": 0, "data": {} }) });
  1. 展望

针对不同的请求生成动态的内容,我们可以通过req.query和req.params等来生成动态内容,在express中,我们传入的body内容,在req.body中并获取不到,需要添加中间件body-parser,需要注意的是这个中间件不能在app全局路由使用,不然会影响到代码到测服的接口,利用http-proxy-middleware转发的接口,所以我们需要单独的设置一个Mock路由,针对路由级别的使用中间件,代码如下

现阶段暂时无法数据联动,也就是对于前端来说,接口变更,还需要手动在ide上修改代码。如果能够开发一套插件,前端只需初始编写一次代码,后面ide自动同步接口变化,然后自动修改代码,不是爽歪歪!

const bodyParser = require;const express = require;const mockRouter = express.Router();// express middleware bodyParser for mock server// for parsing application/jsonmockRouter.use;// for parsing application/x-www-form-urlencodedmockRouter.use(bodyParser.urlencoded;// Api prefix named /mockapp.use;// now you can set mock api use mockRoutermockRouter.use('/ajax-get-info',  => { // use req.body to get request body info console.log; res.send({ "success": true, "code": 0, "data": { // return dynamic JSON name: req.body.name } })});

总结

现在Mock级别的路由已经有了,接下来我们就要准备对应的路由和响应的callback了,添加一个mock文件夹,专门放置一些mock接口的文件,利用node的fs模块引入所有需要mock的接口即可

如果你目前的项目是中小型项目,那么可以使用mockjs或者Mock Server之类,如果项目比较大,还是建议使用在线mock平台。

const path = require;const mockDir = path.resolve;fs.readdirSync.forEach(file => { const mock = require(path.resolve; // mockRouter就是上面Mock路由即可 mockRouter.use(mock.api, mock.response);});

2、Vue-cli3.x的基本知识,相对比于Vue-cli2.x的版本,把webpack的配置封装出来,抛出一些外在接口去修改webpack配置,我们需要了解的是针对开发模式express的使用(内部使用webpack-dev-serve),Vue-cli3.0需要的是在适当的时机处理开发模式的express实例,来达到Mock的目的

module.exports = { dev: { before:  => { // app就是底层的express实例,上面针对express实例的操作,全部换成app即可 } } }

3、至于mock的文件下面的js文件就是我们需要挂载到express的mock接口的信息,下面给出一个实例,其他仿照即可,一个js文件代表一个mock接口

// 注意,由于是针对子路由级别的,前端调用的url为/mock/get-infomodule.exports = { api: '/get-info', response:  => { // 由于添加了body-parser中间件,所以可以解析传入的body,这里就可以用来动态的生成JSON const flag = req.body.flag; console.log; res.send( { success: flag, code: 0, data: [], message: '获取信息成功', }, ); },};

四:结合上面的几点整合处理

五:其他几种方式的Mock接口

mock.js去,给出官网,它会修改原生的XMLHttpRequest来拦截ajax请求,同时提供强大的根据模板生成数据 fastmock,类似本地Mock,数据放在了外网,团队配合可以选择,具体使用见链接 后端Controller生成静态JSON,不推荐,后端不会吊我们的,搞不好会干架,哈哈

六:总结

前端工程化的出现能够让前端做的事情很多很多,技术的广度能够支持你做一些有意思的事情。首先这个可以做一些优化,比如本地的Mock可以使用mock.js纯处理一些数据的生成工作。注意mock接口的url和自己proxy的接口不要冲突。使用Vue-cli3.0,它不仅是封装了webpack的配置,同时提供了自己一套插件机制,接下来写一个简单的cli插件自动化完成这些操作,敬请期待。欢迎评论交流。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

TAG标签:
版权声明:本文由澳门新葡8455手机版发布于Web前端,转载请注明出处:浅谈前端mock,0中集成MockApi的不二等秘书诀自己