内容简介:Nodejs 自从 2009 年被开发出来以后,至今已经走过了 9 个年头,目前最新的稳定版已经到了 10.13。从问世以后,Nodejs 就深受前端工程师的喜欢。在携程内部,Nodejs 也是应用广泛,从开发工具到 web 应用,从客户端到服务端,都能见到它的身影。我们也从最初用 Node.js 来完成前后端的架构分离到最近使用 GraphQL 来做微服务,机票部门在 Node.js 的应用探索上越走越宽。在机票事业部前端开发的 web1.0 时代,整个前后端代码耦合在一起,采用的是典型的服务端 MVC
Nodejs 自从 2009 年被开发出来以后,至今已经走过了 9 个年头,目前最新的稳定版已经到了 10.13。从问世以后,Nodejs 就深受前端工程师的喜欢。
在携程内部,Nodejs 也是应用广泛,从开发 工具 到 web 应用,从客户端到服务端,都能见到它的身影。我们也从最初用 Node.js 来完成前后端的架构分离到最近使用 GraphQL 来做微服务,机票部门在 Node.js 的应用探索上越走越宽。
一、前后端分离
在机票事业部前端开发的 web1.0 时代,整个前后端代码耦合在一起,采用的是典型的服务端 MVC 架构。
在这样的开发模式下,会存在一些问题和痛点:
1)前后端代码耦合在一起,维护成本比较大,前端的同学不熟悉服务端开发语言,服务端同学也不熟悉前端的交互;
2)展示逻辑和业务逻辑混在在一起,前后端开发同学的职责不明确,有些需求前端说这个逻辑在 view 层,应该后端改,后端说,前端做兼容处理;
3)项目的扩展性比较低,维护性差,迭代速度慢。
在传统的 MVC 模式中,由于 view 层所承载的内容过多,导致 view 层这一块和前端的耦合太多,整体开发效率低下。
能否将这个剥离出来,让前后端集中力量关注自己的领域呢?答案是肯定的,我们将客户端和服务端隔离开,服务端负责数据聚合,提供标准的 restful 接口,前端负责数据渲染。
在机票 H5 实践前后端分离过程中,我们改进了技术架构,在前端的应用层,采用 PM2+Node.js(8.9.4)+Express(4.0)框架,内部基于携程基础框架 ctriputil,同时对一些常用功能的封装,如 Redis 的调用,ABTest 的获取,Qconfig 的集成。
为什么选择 Nodejs 呢?
1)Nodejs 采用的是 V8 引擎,运行的是 javascript 代码,对于前端同学来说,学习成本低;
2)Nodejs 是事件驱动的,非阻塞性 I/O,非常适合对于前端这种 IO 密集型的应用;
3)社区活跃度高,有大量的库可以被使用;
4)NPM 生态圈内容丰富;
5)客户端代码和应用端可以共享模版和部分逻辑,适合浏览器及服务端代码共用。
在客户端这一层,选用 vue.js ,依托于公司的 lizard.lite 框架,采用 wbebpack 作为构建工具,并通过结合 UT 来提升开发质量。
在 vue 的使用上采用 Vuex 进行状态管理,用 Vue Router 进行路由管理以及用 Lizard.lite 进行 model 层管理(如数据获取、转换、缓存、日志记录、环境切换等)。对于基础数据信息采用 Localstore 进行本地持久化存储,对于状态数据采用 Sessionstore 进行管理,确保状态在当次 session 中是有效的。
自动化代码集成方面我们采用 ESlint\TSlint 做一些基本的语法检查,同时使用 mocha 进行单元测试,确保开发质量,同时按 controller\model\fue 进行分层,确保每个模块之间相对独立。
整个改造后的架构具备以下特性:
模块化:ES6 import + System.import + vue 单文件组件;
单页路由控制: vue-router + async component;
服务器通信: 同构的 businiess model(LizardLite.AbsModel);
状态管理: vuex store;
代码质量: standardjs + eslint + mocha + chai;
构建发布: webpack dev server + npm scripts + html-minifier/uglify js/clean css;
整个机票 H5 预订流程采用单页 +SSR 模式进行开发,获得了 APP-LIKE 式的体验。
针对直接 Landing 页面,采用 APPSHELL 进行服务端加载骨架,提升首屏可视加载速度,对非 Landing 页面采用 SPA 模式,提升后续页面加载速度流畅度,对于搜索引擎的爬虫,会自动识别并进行服务端渲染,做到客户端和服务端代码复用。
为降低每个页面的资源加载耗时,会对页面资源文件进行拆分和后续页面资源的预加载,同时利用大数据进行用户行为的预测以及接口数据预处理,使得页面速度的加载耗时得到比较大的提升。
二、Node.js 与 restfulAPI
在采用 Node.js 来完成前后端分离后,整个前台的架构分为三大块,一个是以浏览器渲染为主的客户端,二是 Node.js 为主的应用端,三是前台的数据聚合层,在前台的数据聚合层采用 JAVA 作为主要开发语言,对接后台底层的接口。
在 2016 年以来,机票前台开发组开始推行敏捷开发,采用 scrum 的模式进行敏捷管理,并组建比较多的敏捷团队,由于有些敏捷团队比较小,人数相比较少,团队中经常客户端、服务端都只有 1 个或者 2 个同学,如果遇到一个项目是服务端逻辑比较多的时候,服务端资源会爆掉,在遇到改版类项目时,前端资源会爆掉,但由于前后的技术栈不统一,团队内部开发资源相互协调起来比较困难。
如何让团队的效能发挥到最大是我们一直在思考的问题,于是我们在 scrum 团队尝试技术栈统一,将前台的数据聚合层改为用 Node.js 来实现,使得整个团队内部以前端开发工程师为主。
整个 Node 层的架构和 H5 应用层类似,也是采用 PM2+Node.js(8.9.4)+Express(4.0)+CtripUtil,为了提供标准的 restfulAPI,我们在服务入口做了自动化的注册方式,方便客户端接入;
在 Node 层内部针对后台接口的调用做了深度封装,在使用上更加方便快捷,同时接入公司 cat/clog 等通用日志系统。
经过对服务端的改造以及技术栈的统一,整个团队的效能也得到了提升,用 Node.js 实现的接口在上线后性能稳定,整体耗时控制在 50ms 以内。
三、RestfulAPI->GraphQL
经过了前面用 Node.js 进行标准的 restfulAPI 开发尝试,有越来越多 Node.js 实现的接口上线,整个前台的架构如下:
在经历过几个版本迭代之后,我们发现了一些新的问题:
1)不同版本的客户端需求不同,相同的接口需要针对不同的版本做不同的处理;
2)不同的客户端对于契约的需求也不一样,比如 PC 由于屏幕尺寸的关系,在界面设计上给用户的信息要比 APP 多的多,PC 与 APP 在显示的信息上是有差异的,相同的契约数据下发对于某一端来说会存在浪费,从而加大网络开销,
3)在 APP 上也会存在着版本之间的差异,比如 7.15 的版本和 7.16 的版本,7.16 上了一些新的功能,加了一些新的 fetch,如果统一下发给前端,对于老的版本也是也是资源上的浪费,
4)客户端在某些时候需要调用多个接口汇总数据一起显示,某些情况下又要分开调用,对于服务来说,动态可扩展的架构尤为重要,
5)前端在 model 层使用的结构和服务端结构可能会存在差异性,如何磨平这些差异,也非常考验开发同学的技术能力;
在这个时候,GraphQL 进入到了我们的视野。GraphQL 是一种新的 API 标准,它提供一种更高效、更加灵活的数据查询方式,在 2015 年被 Facebook 正式开源。
其在本质上是一种基于 API 的查询语言,是对 restfulAPI 的一种封装,目的在于构建一种更加易用的服务,通过 GraphQL,客户端可以很方便的获取所需要的数据。
比如下面的这个例子,获取 ID 为 1 的城市信息,只要返回的 schema 保护 ID,name,Code 即可,其中 name 为重定义 schema。
复制代码
Request: { city: getCityInfo(id:1) { ID name: Name Code } } Response: { "data": { "city": { "ID":1, "name":" 北京 ", "Code":"BJS" } } Schema: module.exports = new GraphQLObjectType({ 'name':'CityInfo', 'description':'城市实体', 'fields': { 'Code': { 'description':'城市三字码', 'type': GraphQLString }, 'ID': { 'description':'城市 ID', 'type': GraphQLInt }, 'Name': { 'description':'城市名称', 'type': GraphQLString } } })
GraphQL 和传统的 restAPI 相比:
1)数据获取:GraphQL 可以按需获取,通过调用方指定 schema 返回不同报文,RestfulAPI 则是下发相同的结构;
2)类型系统,强校验:GraphQL 使用 Type System 来定义 API,公开的类型都是通过 SDL 模式进行编写,统一前后端契约结构,便于使用;
3)URL 入口:Rest 不同的请求入口不同,在请求的 URL 上需要做区分,GraphQL 则是一个入口 (/graphql?query=),通过调用的 request 来区分;
4)调用方式:Rest 获取多个不同接口数据时,需要并发调用多次,而 GraphQL 可以合并查询,降低网络开销;
于是我们开始在团队内部试点 GraphQL,在技术架构上采用 PM2+Node.js+Express+Express-GraphQL,选用 Express-GraphQL 作为核心中间件,统一客户端的请求入口为 /graphql?query=*,由调用端来决定自己需要哪些数据。
四、总结
Node.js 在机票团队从早期的前后端分离到 GraphQL 的实践,目前已经深度应用到前端组的各个模块,现在机票前端应用层已全部采用 Node.js 来实现。
有近 20+ 接口采用 Node.js 来开发,其中一大半是通过 GraphQL 来实现,日均的流量在 200W 左右,整体 Node 服务端性能稳定,后续我们还将继续拓宽 Node.js 的使用场景,使其发挥更大的价值。
更多内容,请关注前端之巅。
以上所述就是小编给大家介绍的《从前后端分离到 GraphQL,携程如何用 Node 实现?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- php如何实现session,自己实现session,laravel如何实现session
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
- Docker实现原理之 - OverlayFS实现原理
- 为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?
- 自己实现集合框架(十):顺序栈的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
两周自制脚本语言
[日]千叶 滋 / 陈筱烟 / 人民邮电出版社 / 2014-6 / 59.00元
《两周自制脚本语言》是一本优秀的编译原理入门读物。全书穿插了大量轻松风趣的对话,读者可以随书中的人物一起从最简单的语言解释器开始,逐步添加新功能,最终完成一个支持函数、数组、对象等高级功能的语言编译器。本书与众不同的实现方式不仅大幅简化了语言处理器的复杂度,还有助于拓展读者的视野。 《两周自制脚本语言》适合对编译原理及语言处理器设计有兴趣的读者以及正在学习相关课程的大中专院校学生。同时,已经......一起来看看 《两周自制脚本语言》 这本书的介绍吧!
RGB CMYK 转换工具
RGB CMYK 互转工具
HEX HSV 转换工具
HEX HSV 互换工具