基于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入门详解(多篇文章结合)
Mar 07 NodeJs
windows系统下简单nodejs安装及环境配置
Jan 08 NodeJs
Nodejs中的this详解
Mar 26 NodeJs
详解nodejs 文本操作模块-fs模块(三)
Dec 22 NodeJs
用nodejs搭建websocket服务器
Jan 23 NodeJs
NodeJS处理Express中异步错误
Mar 26 NodeJs
深入nodejs中流(stream)的理解
Mar 27 NodeJs
详解nodeJS之二进制buffer对象
Jun 03 NodeJs
windows系统下更新nodejs版本的方案
Nov 24 NodeJs
Nodejs中获取当前函数被调用的行数及文件名详解
Dec 12 NodeJs
nodeJS进程管理器pm2的使用
Jan 09 NodeJs
NodeJs实现简易WEB上传下载服务器
Aug 10 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
全国中波电台频率表
2020/03/11 无线电
PHP syntax error, unexpected $end 错误的一种原因及解决
2008/10/25 PHP
php使用exec shell命令注入的方法讲解
2013/11/12 PHP
php格式化日期和时间格式化示例分享
2014/02/24 PHP
PHP用户验证和标签推荐的简单使用
2016/10/31 PHP
javascript indexOf函数使用说明
2008/07/03 Javascript
javascript中的float运算精度实例分析
2010/08/21 Javascript
JavaScript中的字符串操作详解
2013/11/12 Javascript
NodeJS学习笔记之Connect中间件模块(一)
2015/01/27 NodeJs
js创建jsonArray传输至后台及后台全面解析
2016/04/11 Javascript
使用Ajax生成的Excel文件并下载的实例
2016/11/21 Javascript
详解vue填坑之解决部分浏览器不支持pushState方法
2018/07/12 Javascript
JavaScript惰性求值的一种实现方法示例
2019/01/11 Javascript
vue图片上传本地预览组件使用详解
2019/02/20 Javascript
jquery3和layui冲突导致使用layui.layer.full弹出全屏iframe窗口时高度152px问题
2019/05/12 jQuery
element-ui 本地化使用教程详解
2019/10/28 Javascript
python实现复制整个目录的方法
2015/05/12 Python
python控制台中实现进度条功能
2015/11/10 Python
Windows系统下多版本pip的共存问题详解
2017/10/10 Python
浅谈python函数之作用域(python3.5)
2017/10/27 Python
浅谈Matplotlib简介和pyplot的简单使用——文本标注和箭头
2018/01/09 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
2019/01/04 Python
python批量爬取下载抖音视频
2019/06/17 Python
简单了解Django ContentType内置组件
2019/07/23 Python
python如何运行js语句
2020/09/09 Python
KIKO MILANO英国官网:意大利知名化妆品和护肤品品牌
2017/09/25 全球购物
Aeropostale官网:美国著名校园品牌及青少年服饰品牌
2019/03/21 全球购物
行政助理岗位职责范文
2013/12/03 职场文书
开学寄语大全
2014/04/08 职场文书
中餐厅经理岗位职责
2014/04/11 职场文书
小学生优秀评语大全
2014/04/22 职场文书
员工合理化建议书
2014/05/19 职场文书
十佳青年事迹材料
2014/08/21 职场文书
承诺书的内容有哪些,怎么写?
2019/06/21 职场文书
PyTorch device与cuda.device用法
2022/04/03 Python
Java8利用Stream对列表进行去除重复的方法详解
2022/04/14 Java/Android