前后端分离的架构中,前后端同学约定好接口后就可以并行开发,最后双方再进行接口的联调。不过实际开发时,前后端联调会遇到下面这些问题,这些问题无疑中会影响联调的效率,拉长整个开发的周期。
前端和后端开发的进度不一致,例如前端同学已经按照交互完成了页面的开发,但是后端同学此时还不能及时提供出接口,此时前端同学会陷入“等接口”的境地。
好不容易等来了接口,前端同学联调后发现接口存在一些问题,再把问题反馈给后端同学。后端同学本地复现问题,修改完接口后再重新部署,然后通知给前端同学。前端同学这时再重新调用,测试接口是否正常,如果又发现了新的问题,再重复上面的流程...
首先对于第一个“等接口”的痛点,只有后端同学及时提供接口才能从根本上解决,比如让后端同学先开发,前端同学稍后再介入开发。Sadly,现实很多模块都是前后端同学同时开发,碰到这种情况,我们除了“死等到底”,还可以“提前准备”。前后端同学可以在开发前,约定好接口,具体的形式可以有:
=> 看似省事,实则后患无穷。可能导致双方记不清细节,以及日后出现问题后,容易互相甩锅。
=> 写word、markdown文档,更新到公司的wiki上。更好一点的话,使用swagger生成文档。
约定好接口后,前后端同学并行开发。后端如若不能及时提供接口,前端可以本地模拟数据或者使用一些接口模拟工具,详细内容会在后面介绍。
针对第二个痛点,前端其实可以进行“工作转移”。具体就是前端同学本地开发完,确认好各个接口已经按照接口文档约定的参数传参后,无需做后端同学的陪练,可以把最新代码发布到某一个开发环境,让后端同学在写完接口后,在开发环境通过页面进行联调。服务端接口如果有问题,后端同学自己修改完重新发布后,再自己从前端页面测试。如果实在需要更改或再增加参数,再去找前端同学。这样前端同学就可以从“改接口-调接口”的循环圈中解脱出来,把更多精力地放在开发工作上。
本节三种姿势介绍如何本地模拟数据,如果不需要可以跳过。
在业务代码里面使用假数据供页面使用,等到后端提供接口后,再将页面的假数据注释掉,改成调用接口。
缺点:
这样会导致业务代码里面混杂了大量冗余代码;
把假数据放到json文件中,本地请求json文件。
示例(数据为假数据):
{
"Code": 200,
"Message": "",
"Data": {
"items": [{
"exp1": "fbcc7d9e-9be1",
"exp2": "xxx",
"enabled": true,
"size": 0,
"createBy": "",
"createTime": "2019-07-12T02:56:54.17+08:00",
"updateBy": "",
"updateTime": "2019-08-06T03:03:37.859+08:00",
"comment": ""
}
],
"totalCount": 1
}
}
业务代码里:
import jsonData from './data.json';
通过jsonData(例如jsonData.Data.items)即可获取到json数据
优点:比上一个方法好一些,因为没有直接在业务代码里写入大量的假数据。
缺点:如果希望模拟50条数据的返回,简单粗暴地硬写50条(大量复制粘贴+修改)又有些浪费时间,不够优雅。
使用Mock.js,按照Mock模版生成指定数量的随机数据
import Mock from 'mockjs';
var responseData = Mock.mock({
Code:200,
Message:"",
Data:{
'items|10': [{
"exp1": /[a-z][0-9]{8}-[0-9]{4}/,
"exp2|1": [ "xxx", "xxx", "xxx"],
"enabled|1": [true, false],
"size": 0,
"createBy":"@cname",
"createTime": "@now(yyyy-MM-dd) @increment(1):00:00",
"updateBy": "",
"updateTime": "@now(yyyy-MM-dd) @increment(1):01:00",
"comment": ""
}],
"totalCount": 10
}
})
export default responseData;
简单解释下:
这里是mock.js的语法,'items|10':{xxx}表示:items是一个数组,里面包含了10个对象,每个对象都包含exp1、exp2等属性。其中exp1返回一个按照正则表达式生成的字符串。"exp2|1":[]是从数组中随机选一个元素,作为exp2最后的属性值。
【补充】一些基本的Mock知识
Mock方式:
代码拦截
代码工具(Fiddler、Charles等)
Mock.js 规范:
(1)数据模版定义规范(DTD)
数据模板中的每个属性由 3 部分构成:属性名、生成规则、属性值:
// 属性名 name ; 生成规则 rule ; 属性值 value
'name|rule':value
其中属性值类型:
String、Number、Boolean、Object、Array、Function、RegRxp
生成规则(可选)有7种格式:
'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
dmin最少小数位,dmax最多小数位
step递增
dcount固定位数的小数位
(2)数据占位符定义规范(DPD)
格式:@占位符
例如@cname、@date、@image等,不做展开了。
了解更多关于mock.js:
这样可以方便得按照我们定义的Mock模版,优雅、快速、随机生成规定数量的数据。
以egg为例,在controller这里,把本来调用真实后端接口注释掉,用Mock数据:
* getxxxList() {
let ctx = this.ctx;
try {
let responseData = Mock.mock({
'items|10': [{
"exp1": /[a-z][0-9]{8}-[0-9]{4}/,
"exp2|1": ["xxx", "xxx", "xxx"],
"enabled|1": [true, false],
"size": 0,
"createBy": "",
"createTime": "@now(yyyy-MM-dd) @increment(1):00:00",
"updateBy": "",
"updateTime": "@now(yyyy-MM-dd) @increment(1):01:00",
"comment": ""
}],
"totalCount": 10
})
ctx.body = {
Code: 200,
Data: responseData,
Message: ""
};
} catch (ex) {
this.logger.error('Execute xxx Failed:%j', ex);
ctx.body = {
Code: 100,
Data: null,
Message: "xxx接口发生错误"
}
}
}
优点:
前后端分离、用法简单,方便扩展,通过随机数据可以模拟各种场景。
缺点:
本节介绍了三种姿势本地模拟数据,可以说本地模拟数据是种简单直接的解决方法,可以满足基本的开发需要,不过很多开发过程中要考虑的情况,仅仅依靠前端同学模拟数据,是不足以解决的。下面就介绍一些mock工具。这些工具能够确保前端在开发过程中的模拟数据可控,且在使用之后不会对前端或者服务端的流程有任何影响。
常见的前端接口模拟工具有RAP2,EasyMock,NEI,YApi,Apiary等,这些工具基于Mock.js来进行数据模拟,并在此基础上做了不同的扩展。这里重点介绍RAP2和Easy Mock,其他常见前端接口模拟工具的特性也会在后面列出。
前后端分离开发,Mock.js可以解决前端依赖后端提供接口后,才能请求数据的限制。不过信息同步的问题随之产生,可能出现后端修改接口,前端没有同步的情况。RAP2则是将前端和后端拉到一个团队仓库,通过共享一个仓库,让前端和后端双方同学都可以进行管理,同步性好,并且也可以查看接口修改的记录。
阿里妈妈MUX前端团队出品的开源接口管理工具RAP第二代
相关链接:
第一次使用RAP2,会首先让你邮箱注册,注册成功后,就可以开始新建仓库了。不过在正式创建仓库前,这里先介绍一些基本的概念:
新建一个仓库,填写一些基本信息:名称、简介、成员、协同仓库;即可以看到建好的仓库:
点击仓库名即可进入仓库,仓库中已经初始化了一个示例模块,示例模块中有一个示例接口,可以扫一眼示例接口,这些可以帮助新人快速上手。
下面可以自己新建一个模块(示例模块右边,可新建模块),然后在新模块中一个接口:
接下来可以设置请求参数和响应内容,其中请求参数、响应内容有两种添加方式,可以逐个添加字段或者采用导入的方式:
采用导入的方式,这里导入:
{
"id": "@id",
"cname": "@cname",
"string": "@string(11)",
"float": "@float(0,10)",
"int": "@integer(60,70)",
"boolean": true,
"array|2": [
{
"id": "@integer(1,10)",
"name": "cname"
}
],
"actionType|1": [
"click_url",
"open_resource_detail",
"open_resource_search"
],
"title": "@ctitle",
"city": "@city",
"email": "@email",
"ip": "@ip",
"url": "@url",
"cfirst": "@cfirst",
"clast": "@clast",
"cword": "@cword('123456')",
"csentence": "@csentence(1,5)",
"csentence5": "@csentence(5)",
"cparagraph": "@cparagraph(1,3)"
}
导入后可以看到:
在接口页面,通过点击“插件”可以看到仓库、在线编辑的地址、请求接口地址,前端直接用jquery的ajax请求线上接口地址就能看到返回结果。
另外RAP2提供了Mock插件,不过目前只支持Kissy和jQuery。使用时需要在项目中加上一行插件代码:
<script type="text/javascript" src="http://{{domainName}}/rap.plugin.js?projectId={{projectId}}&mode={{mode}}"></script>
具体使用规则可查阅RAP2的用户手册
值得注意的是,任何人的操作动作都有所记录,可以点击“首页”查看。
使用感受:RAP2界面简洁、交互友好、上手快,可界面编辑API,不过一个个定义接口返回字段需要花费较长时间。
如果担心使用线上RAP2可能会外泄公司内部的接口文档,可以git clone RAP2的项目,在公司内部搭建个RAP2。具体方法笔者还没有尝试,这里放些参照文章。
https://github.com/thx/RAP/wiki
https://www.cnblogs.com/operationhome/p/10038469.html
杭州大搜车无线架构团队提供的一个可视化,并且能快速生成 模拟数据 的持久化服务。
特性:
了解更多:https://github.com/easy-mock/easy-mock
直观感受:
可以使用EasyMock的扩展语法,通过添加function来返回响应式数据,示例:
{
"data": {
"age|1-100": 16,
"province": "@province",
"city": "@city",
"intro": "@cparagraph",
"default": 'shenzhen',
"address": function({
_req,
Mock
}) {
if (_req.query.name === 'Peter') {
return _req.query.name + ' lives in' + Mock.mock('@city')
} else {
return this.default
}
}
}
}
可以预览下返回:
这样就可以根据不同的请求参数,返回响应式数据。
NEI 是网易杭研前端技术部推出的一款产品,功能较RAP2要丰富,不过没有开源。
具体提供的功能有:
了解更多,https://zhuanlan.zhihu.com/p/23191873
YApi是去哪儿网移动架构组开发的一个开源项目
特性:
了解更多:https://github.com/YMFE/yapi
使用感受:直观感受功能比RAP2更丰富,不过操作不如RAP2顺畅,比如编辑时不能实时看到数据,要点击“预览”才能查看。
可以在线模拟测试,因为该平台具备模拟服务器测试服务。可以把设计好的程序在线测试、验证。可以快速生成api文档,导出离线版文档,功能完善,不过没有开源。
在前后端分离的架构中,为了让前端同学在前后端联调时摆脱“等接口-改接口-调接口”的尴尬境地,减少双方的沟通成本、时间成本,提高项目整体开发效率,缩短开发周期。前端同学可以模拟数据,具体可以前端本地模拟数据,或者使用一些前端接口模拟工具。至于哪种方法更好,还需要视具体情况而定。比如一个比较小的项目,前端本地模拟数据足矣,如果为了一个小项目,还需要本地搭建一套接口模拟工具,倒有些“杀鸡用牛刀”了。不过长远而看,使用前端接口模拟工具会带来很多的便利,值得我们花时间去了解和使用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。