基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架


Posted in NodeJs onSeptember 26, 2014

前言

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

基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架

由于后端提供的接口方式可能多种多样,同时开发人员在编写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工作原理图及相关开发过程图览

基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架

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

下面是一个简单的例子:

【例一】

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

{

    "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

// 引入模块

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最后'.'号后面的单词作为方法名

ModelProxy.create( 'Search.getItem' );

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

ModelProxy.create( {

    getName: 'Session.getUserName',

    getMyCarts: 'Cart.getCarts'

} );

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

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

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

ModelProxy.create( 'Search.*' );

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

【例二】 合并请求

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 );

    } );

【例三】 依赖请求

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

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

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

<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 是阿里集团研发的前后端统一接口规范及相关工具集合的统称

NodeJs 相关文章推荐
轻松创建nodejs服务器(9):实现非阻塞操作
Dec 18 NodeJs
NodeJS使用jQuery选择器操作DOM
Feb 13 NodeJs
Nodejs实现批量下载妹纸图
May 28 NodeJs
Windows 系统下设置Nodejs NPM全局路径
Apr 26 NodeJs
nodejs简单实现操作arduino
Sep 25 NodeJs
nodejs个人博客开发第六步 数据分页
Apr 12 NodeJs
NodeJs安装npm包一直失败的解决方法
Apr 28 NodeJs
nodejs遍历文件夹下并操作HTML/CSS/JS/PNG/JPG的方法
Nov 01 NodeJs
详解从NodeJS搭建中间层再谈前后端分离
Nov 13 NodeJs
纯异步nodejs文件夹(目录)复制功能
Sep 03 NodeJs
浅谈vue websocket nodeJS 进行实时通信踩到的坑
Sep 22 NodeJs
浅谈Node的内存泄露问题
May 06 NodeJs
基于NodeJS的前后端分离的思考与实践(二)模版探索
Sep 26 #NodeJs
基于NodeJS的前后端分离的思考与实践(一)全栈式开发
Sep 26 #NodeJs
Nodejs Post请求报socket hang up错误的解决办法
Sep 25 #NodeJs
Nodejs实现的一个简单udp广播服务器、客户端
Sep 25 #NodeJs
Nodejs异步回调的优雅处理方法
Sep 25 #NodeJs
nodejs命令行参数处理模块commander使用实例
Sep 17 #NodeJs
nodejs npm package.json中文文档
Sep 04 #NodeJs
You might like
在PHP的图形函数中显示汉字
2006/10/09 PHP
PHP截取汉字乱码问题解决方法mb_substr函数的应用
2008/03/30 PHP
Dwz与thinkphp整合下的数据导出到Excel实例
2014/12/04 PHP
表单项的name命名为submit、reset引起的问题
2007/12/22 Javascript
javascript闭包的理解和实例
2010/08/12 Javascript
jquery 多行文本框(textarea)高度变化
2013/07/03 Javascript
js实现两个值相加alert出来精确到指定位
2013/09/25 Javascript
JavaScript 里的类数组对象
2015/04/08 Javascript
jQuery中deferred对象使用方法详解
2016/07/14 Javascript
JavaScript基于Dom操作实现查找、修改HTML元素的内容及属性的方法
2017/01/20 Javascript
详解Vue2.0里过滤器容易踩到的坑
2017/06/01 Javascript
JavaScript中in和hasOwnProperty区别详解
2017/08/04 Javascript
浅谈Angular路由守卫
2017/08/26 Javascript
node.js实现微信JS-API封装接口的示例代码
2017/09/06 Javascript
详解react-router 4.0 下服务器如何配合BrowserRouter
2017/12/29 Javascript
Vue利用History记录上一页面的数据方法实例
2018/11/02 Javascript
一些手写JavaScript常用的函数汇总
2019/04/16 Javascript
从零搭一个自用的前端脚手架的方法步骤
2019/09/23 Javascript
基于PHP pthreads实现多线程代码实例
2020/06/24 Javascript
js实现简单的随机点名器
2020/09/17 Javascript
Python 获取新浪微博的最新公共微博实例分享
2014/07/03 Python
Python网络爬虫项目:内容提取器的定义
2016/10/25 Python
教你学会使用Python正则表达式
2017/09/07 Python
Django组件content-type使用方法详解
2019/07/19 Python
Python使用xpath实现图片爬取
2020/09/16 Python
Matplotlib中rcParams使用方法
2021/01/05 Python
HTML5 客户端数据库简易使用:IndexedDB
2019/12/19 HTML / CSS
咖啡蛋糕店创业计划书
2014/01/28 职场文书
模范家庭事迹材料
2014/02/10 职场文书
主管会计岗位责任制
2014/02/10 职场文书
信息服务专业毕业生求职信
2014/03/02 职场文书
教师对学生的寄语
2014/04/03 职场文书
2014年组织部工作总结
2014/11/14 职场文书
单位租房协议范本
2014/12/03 职场文书
元宵节寄语大全
2015/02/27 职场文书
nginx优化的六点方法
2021/03/31 Servers