Midway-ModelProxy — 轻量级的接口配置建模框架

前言

使用Node做前后端分离的开发模式带来了一些性能及开发流程上的优势(见《前后端分离的思考与实践 一》), 但同时也面临不少挑战。在淘宝复杂的业务及技术架构下,后端必须依赖Java搭建基础架构,同时提供相关业务接口供前端使用。Node在整个环境中最重要 的工作之一就是代理这些业务接口,以方便前端(Node端和浏览器端)整合数据做页面渲染。如何做好代理工作,使得前后端开发分离之后,仍然可以在流程上 无缝衔接,是我们需要考虑的问题。本文将就该问题做相关探讨,并提出解决方案。


由于后端提供的接口方式可能多种多样,同时开发人员在编写Node端代码访问这些接口的方式也有可能多种多样。如果我们在接口访问方式及使用上不做统一架构处理,则会带来以下一些问题:

1. 每一个开发人员使用各自的代码风格编写接口访问代码,造成工程目录及编码风格混乱,维护相对困难。
2. 每一个开发人员编写自己的mock数据方式,开发完毕之后,需要手工修改代码移除mock。
3. 每一个开发人员为了实现接口的不同环境切换(日常,预发,线上),可能各自维护了一些配置文件。
4. 数据接口调用方式无法被各个业务model非常方便地复用。
5. 对于数据接口的描述约定散落在代码的各个角落,有可能跟后端人员约定的接口文档不一致。
6. 整个项目分离开发之后,对于接口的联调或者测试回归成本依然很高,需要涉及到每一个接口提供者和使用者。

于是我们希望有这样一个框架,通过该框架提供的机制去描述工程项目中依赖的所有外部接口,对他们进行统一管理,同时提供灵活的接口建模及调用方式, 并且提供便捷的线上环境和生产环境切换方法,使前后端开发无缝结合。ModelProxy就是满足这样要求的轻量级框架,它是Midway Framework 核心构件之一,也可以单独使用。使用ModelProxy可以带来如下优点:

1. 不同的开发者对于接口访问代码编写方式统一,含义清晰,降低维护难度。
2. 框架内部采用工厂+单例模式,实现接口一次配置多次复用。并且开发者可以随意定制组装自己的业务Model(依赖注入)。
3. 可以非常方便地实现线上,日常,预发环境的切换。
4. 内置river-mock和mockjs等mock引擎,提供mock数据非常方便。
5. 使用接口配置文件,对接口的依赖描述做统一的管理,避免散落在各个代码之中。
6. 支持浏览器端共享Model,浏览器端可以使用它做前端数据渲染。整个代理过程对浏览器透明。
7. 接口配置文件本身是结构化的描述文档,可以使用river工具集合,自动生成文档。也可使用它做相关自动化接口测试,使整个开发过程形成一个闭环。

ModelProxy工作原理图及相关开发过程图览

在上图中,开发者首先需要将工程项目中所有依赖的后端接口描述,按照指定的json格式,写入interface.json配置文件。必要时,需要 对每个接口编写一个规则文件,也即图中interface rules部分。该规则文件用于在开发阶段mock数据或者在联调阶段使用River工具集去验证接口。规则文件的内容取决于采用哪一种mock引擎(比 如 mockjs, river-mock 等等)。配置完成之后,即可在代码中按照自己的需求创建自己的业务model。

下面是一个简单的例子:

【例一】

  • 第一步 在工程目录中创建接口配置文件interface.json, 并在其中添加主搜接口json定义

1

2

3

4

5

6

7

8

9

10

11

12

13

14

{

"title": "pad淘宝项目数据接口集合定义",

"version": "1.0.0",

"engine": "mockjs",

"rulebase": "./interfaceRules/",

"status": "online",

"interfaces": [ {

"name": "主搜索接口",

"id": "Search.getItems",

"urls": {

"online": "http://s.m.taobao.com/client/search.do"

}

} ]

}

  • 第二步 在代码中创建并使用model

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

// 引入模块

var ModelProxy = require( 'modelproxy' );

// 全局初始化引入接口配置文件  (注意:初始化工作有且只有一次)

ModelProxy.init( './interface.json' );

// 创建model 更多创建模式请参后文

var searchModel = new ModelProxy( {

searchItems: 'Search.getItems'  // 自定义方法名: 配置文件中的定义的接口ID

} );

// 使用model, 注意: 调用方法所需要的参数即为实际接口所需要的参数。

searchModel.searchItems( { q: 'iphone6' } )

// !注意 必须调用 done 方法指定回调函数,来取得上面异步调用searchItems获得的数据!

.done( function( data ) {

console.log( data );

} )

.error( function( err ) {

console.log( err );

} );

ModelProxy的功能丰富性在于它支持各种形式的profile以创建需要业务model:

  • 使用接口ID创建>生成的对象会取ID最后’.’号后面的单词作为方法名

1

ModelProxy.create( 'Search.getItem' );

  • 使用键值JSON对象>自定义方法名: 接口ID

1

2

3

4

ModelProxy.create( {

getName: 'Session.getUserName',

getMyCarts: 'Cart.getCarts'

} );

  • 使用数组形式>取最后 . 号后面的单词作为方法名
    下例中生成的方法调用名依次为: Cart_getItem, getItem, suggest, getName

1

ModelProxy.create( [ 'Cart.getItem', 'Search.getItem', 'Search.suggest', 'Session.User.getName' ] );

  • 前缀形式>所有满足前缀的接口ID会被引入对象,并取其后半部分作为方法名

1

ModelProxy.create( 'Search.*' );

同时,使用这些Model,你可以很轻易地实现合并请求或者依赖请求,并做相关模板渲染

【例二】 合并请求

1

2

3

4

5

6

7

8

9

10

var model = new ModelProxy( 'Search.*' );

// 合并请求 (下面调用的model方法除done之外,皆为配置接口id时指定)

model.suggest( { q: '女' } )

.list( { keyword: 'iphone6' } )

.getNav( { key: '流行服装' } )

.done( function( data1, data2, data3 ) {

// 参数顺序与方法调用顺序一致

console.log( data1, data2, data3 );

} );

【例三】 依赖请求

1

2

3

4

5

6

7

8

9

10

11

12

13

14

var model = new ModelProxy( {

getUser: 'Session.getUser',

getMyOrderList: 'Order.getOrder'

} );

// 先获得用户id,然后再根据id号获得订单列表

model.getUser( { sid: 'fdkaldjfgsakls0322yf8' } )

.done( function( data ) {

var uid = data.uid;

// 二次数据请求依赖第一次取得的id号

this.getMyOrderList( { id: uid } )

.done( function( data ) {

console.log( data );

} );

} );

此外ModelProxy不仅在Node端可以使用,也可以在浏览器端使用。只需要在页面中引入官方包提供的modelproxy-client.js即可。
【例四】浏览器端使用ModelProxy

1

2

<!-- 引入modelproxy模块,该模块本身是由KISSY封装的标准模块-->

<script src="modelproxy-client.js" ></script>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<script type="text/javascript">

KISSY.use( "modelproxy", function( S, ModelProxy ) {

// !配置基础路径,该路径与第二步中配置的拦截路径一致!

// 且全局配置有且只有一次!

ModelProxy.configBase( '/model/' );

// 创建model

var searchModel = ModelProxy.create( 'Search.*' );

searchModel

.list( { q: 'ihpone6' } )

.list( { q: '冲锋衣' } )

.suggest( { q: 'i' } )

.getNav( { q: '滑板' } )

.done( function( data1, data2, data3, data4 ) {

console.log( {

"list_ihpone6": data1,

"list_冲锋衣": data2,

"suggest_i": data3,

"getNav_滑板": data4

} );

} );

} );

</script>

同时,ModelProxy可以配合Midway另一核心组件Midway-XTPL一起使用,实现数据和模板以及相关渲染过程在浏览器端和服务器端的全共享。关于ModelProxy的详细教程及文档请移步https://github.com/purejs/modelproxy

总结

ModelProxy以一种配置化的轻量级框架存在,提供友好的接口model组装及使用方式,同时很好的解决前后端开发模式分离中的接口使用规范 问题。在整个项目开发过程中,接口始终只需要定义描述一次,前端开发人员即可引用,同时使用River工具自动生成文档,形成与后端开发人员的契约,并做 相关自动化测试,极大地优化了整个软件工程开发过程。

【注】River 是阿里集团研发的前后端统一接口规范及相关工具集合的统称

转载于:https://blog.51cto.com/h2appy/1851564

前后端分离的思考与实践(三)相关推荐

  1. 【转载】前后端分离的思考与实践(五)

    基于前后端分离的多终端适配 前言 近年来各站点基于 Web 的多终端适配进行得如火如荼,行业间也发展出依赖各种技术的解决方案.有如基于浏览器原生 CSS3 Media Query 的响应式设计.基于云 ...

  2. 前后端分离的思考与实践(六)

    原文出处: 淘宝UED - 筱谷 Nginx + Node.js + Java 的软件栈部署实践 起 关于前后端分享的思考,我们已经有五篇文章阐述思路与设计.本文介绍淘宝网收藏夹将 Node.js 引 ...

  3. Java Web前后端分离的思考与实践

    第一节 Java Web开发方式的变化 Web开发虽然是我们常说的B/S模式,其实本质上也是一种特殊的C/S模式,只不过C和S的选择余地相对要窄了不少,而且更标准化.不论是采用什么浏览器和后端框架,W ...

  4. 前后端分离的思考与实践

    前言 为了解决传统Web开发模式带来的各种问题,我们进行了许多尝试,但由于前/后端的物理鸿沟,尝试的方案都大同小异.痛定思痛,今天我们重新思考了"前后端"的定义,引入前端同学都熟悉 ...

  5. 前后端分离的思考与实践(二)

    原文出处: 淘宝UED - Herman 基于前后端分离的模版探索 前言 在做前后端分离时,第一个关注到的问题就是 渲染,也就是 View 这个层面的工作. 在传统的开发模式中,浏览器端与服务器端是由 ...

  6. 【转载】前后端分离的思考与实践(二)

    基于前后端分离的模版探索 前言 在做前后端分离时,第一个关注到的问题就是 渲染,也就是 View 这个层面的工作. 在传统的开发模式中,浏览器端与服务器端是由不同的前后端两个团队开发,但是模版却又在这 ...

  7. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 三十║ Nuxt实战:动态路由+同构...

    上期回顾 说接上文<二九║ Nuxt实战:异步实现数据双端渲染>,昨天咱们通过项目二的首页数据处理,简单了解到了 nuxt 异步数据获取的作用,以及亲身体验了几个重要文件夹的意义,整篇文章 ...

  8. 从壹开始前后端分离 [ vue + .netcore 补程 ] 三十一║ Nuxt终篇:基于Vuex的权限验证探究...

    缘起 哈喽大家好,今天周四啦,楼主明天要正式放假了,这里先祝大家节日快乐咯,希望在家里能继续研究点儿东西吧,今天呢是 nuxt 的最后一篇,主要是对权限登陆进行研究,这一块咱们之前在说第一个项目的时候 ...

  9. 前后端分离实践(试探篇)

    为什么80%的码农都做不了架构师?>>>    按照以往的开发模式,前端人员制作好静态页面交给与后端人员进行动态嵌套开发.迭代模式带来一系列问题,静态页面套成动态后,一些操作.业务. ...

最新文章

  1. Android JSON数据解析(GSON方式)
  2. C语言再学习 -- Xargs用法详解
  3. PHP——smarty模板(第一天)
  4. fort77编译器安装
  5. c++ 虚函数的实现机制
  6. MapReduce详解和WordCount模拟
  7. Linux和Windows下部署BeetleX服务网关
  8. 小姐姐为你解析马爸爸是怎么用大数据“宰你”的
  9. [剑指offer][JAVA]面试题第[33]题[二叉搜索树的后序遍历][单调栈][递归分治]
  10. 韩国ETRI提出实时Anchor-Free实例分割算法CenterMask,代码将开源
  11. python输入y继续运行_Python二三事 - 接触Python(x,y)
  12. 使用文件流的方式将 DataTable 导入到 Excel 中
  13. 写 JSP 的痛点,真的非常痛!
  14. Serv-U和win2003防火墙的设置
  15. 如何在线伪造邮箱发件人,用任意邮箱发送邮件
  16. 计算机课件网站,课件-优秀课件大全-瑞文网课件频道
  17. 服务器名称指示(SNI)是什么东东?
  18. NI的LabView2022工具的安装与使用
  19. 计算机毕业设计(论文+代码+数据库+查重)
  20. 07.RabbitMQ处理幂等性

热门文章

  1. LINQ to XML 建立,读取,增,删,改
  2. 关于定于如何弄的漂亮点
  3. Solaris 上网配置
  4. js filter 用法
  5. 微信公众平台开发(十一) 功能整合
  6. 《智能数据时代:企业大数据战略与实战》一3.5 步步为营
  7. POJ 3667 Hotel(线段树)
  8. c++中的基本知识点
  9. mahout kmeans
  10. HTML5新元素section和article的区别详解