图片来自网络
前端Mock的常见解决方案
Mock数据进行调试是前端构建中不可或缺的一步,常见的前端Mock方案分为4种:
在代码层硬编码
比如有一个函数负责请求某个接口,获得的回返数据,并对该回返数据进行操作。那么可以通过硬编码的方式,直接定义一个数据变量在代码中,该变量保存了回返的Mock数据。这种Mock方法操作比较简单,但缺点也很明显,就是Mock更改了代码逻辑,和代码耦合性太强。而且并不能模拟真实的网络请求的过程,局限性强,覆盖面窄。在前端JS中拦截
典型的解决方案就是Mock.js,通过在业务代码前挂载该JS文件,就可以无痛拦截Ajax请求。这种Mock方式相较于硬编码,虽然实现了Mock与代码的部分解耦,但无法完全和业务代码解耦(因为必须挂载一个JS并进行Mock配置)。虽然提供了大量的Mock API,但是也仍然无法发出真实的网络请求,模拟真实度不够。另外这种方式还存在一些不足,因为是对XHR对象的改写,有些情况下兼容性并不好,比如IE8等低版本浏览器,还有较新的Fetch API也拦截不到。代理软件(Fiddler、Charles)拦截
Fiddler和Charles可以对网络请求进行拦截,将其替换为我们需要的Mock数据,这也不失为一种Mock方式。其优点主要是真实性强,但这种方式操作步骤比较繁琐,不方便统一配置,Mock成本较高。Mock-Server
最合适的方案无外乎搭建独立的Mock-Server,开发的前期阶段,所有的接口都会指向该Mock-Server。因为可能存在跨域的情况,所以一般都需要在开发环境搭配一套接口代理做搭配。这种方案对业务代码完全不具有侵入性,并且通用性强。缺点也很明显,成本高(还需要另起一个Mock-Server服务,并对其进行管理)。
接口定义与Mock数据相结合的方案
其实常见的解决方案便是上面提到的几种,或是在这类的基础上进行调整,但整体思路基本一致。Mock的本质是为了能让接口消费者脱离接口生产者进行开发,但是这个脱离并不是指脱离生产者的接口定义随意开发,接口定义与Mock数据的一致性也是我们必须考虑的一个问题,我们必须要确保Mock出的数据符合接口定义中的要求。所以实际上我们还需要多考虑一个问题:如何让接口定义的维护和Mock结合起来?
很庆幸的是,我们有RAP这项工具。RAP是一款非常棒的工具,它是一个可视化接口管理工具,将所有的接口开发定义以其要求的格式进行管理,并能根据这些定义来产生Mock数据,提供给消费者。
既然有了RAP为我们提供Mock-Server服务,那么我们下一步欠缺的就是如何让代码中的网络请求能直接访问到RAP上。RAP有提供一种插件JS,是在Mock.js的基础上扩展的,可以拦截页面上的请求,但暂时仅支持Kissy和jQuery。为此我们在Koa的基础上,结合RAP提供的NodeJS插件(rap-node-plugin)开发了一组工具,能够将配置中要求拦截的所有请求转发到RAP上,并将RAP生成的数据返回给请求方。另外,考虑到Mock调试中,RAP的Mock规则有限和接口定义文档频繁变更的问题,我们还加入了本地mock解决方案,可以随时随地的更改本地local-mock.js文件,避免频繁的RAP文档编辑。本地mock还支持以函数的形式动态返还Mock数据,大大提升了Mock数据生成的能力。另外,在网络请求Mock中,网络延时有时必不可少,我们通过在接口定义中添加_delay
字段,可以决定让该接口多长时间后返回,其它下划线字段可以按需添加。RAP中的配置:
RAP接口配置
Mock方案实现
方案主要由以下4个组件构成:
mock工具
config.js
包含一些对mock工具的配置
/** * 默认配置 */export default { PATH: '/pc/*', // 默认拦截的路径 USE_RAP: true, // 默认为true,会去寻找并调用RAP上的接口 RAP_CONFIG: { host: 'rap.fe.yeshj.com', //启动的服务主机 port: 80, //端口号 projectId: 115, //RAP配置的项目ID mock: '/mockjsdata/', //RAP前缀 wrapper: '' //不需要包装 } }
filter.js
KOA中间件,会对config中配置的PATH进行请求拦截,并根据相关配置获得请求回返数据,进行一定程度的包装,回返为Mock数据。与接口相关的_delay
操作也在该中间件内实现local_mock.js
负责本地mock规则及数据的存放。_delay
关键字在此配置,header
支持自定义回返头部,body
回返体数据支持以函数的形式进行生成。
module.exports = { "POST /pc/check": { "_delay": 1000, "header": { "Content-Type": "application/json;charset=utf-8" }, "body": function (ctx) { return { "status": 0, "data": { "ctx": ctx } } } }, "POST /pc/info": { "_delay": 0, "header": { "Content-Type": "application/json;charset=utf-8" }, "body": { "data": { "id": "12121212" }, "message": "成功", "status": 0 } } }
rap_connector.js
该组件是对rap-node-plugin的封装,方便调用。
开发环境集成
下面就是如何将mock集成到我们的开发环境中去了。
建立mock目录
该Mock方案因为涉及到配置的调整和本地Mock数据的改写,不适于做成单独的node_module进行封装,所以我们选择将mock方案集成到项目中的构建工具中去,目录层级如下:
Paste_Image.png
package.json中增加新脚本
mock
:
"scripts": { "start": "npm run mock", "mock": "babel-node ./tools/build/server.js --dev --mock"}
在koa中注入mock中间件:
if (argv.mock && config.mockEnable) { let mockFilter = require('../mock/filter.js'); app.use(mockFilter()); }
最后一步的工作很简单,就是在mock/config.js中进行一些简单配置,然后在bash中输入npm start
就可以享受我们整套的mock解决方案了。
作者:可木Changer
链接:https://www.jianshu.com/p/720b12b5d120