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-\u0026gt;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:{    \u0026quot;data\u0026quot;: {        \u0026quot;city\u0026quot;: {            \u0026quot;ID\u0026quot;: 1,            \u0026quot;name\u0026quot;: \u0026quot;北京\u0026quot;,            \u0026quot;Code\u0026quot;: \u0026quot;BJS\u0026quot;    }  }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实现?\n相关推荐

  1. 前后端分离和微服务_为什么说微服务,要从前后端分离开始?一文带你揭秘深入微服务...

    前言 既要低头赶路,又要抬头望天,科技是为人服务的,任何技术背后都有更深层次的考量. 之前的文章中咱们聊了很多微服务的相关内容,简而言之,微服务的本质,就是一种可以加速分工.促进合作的新协作机制.知其 ...

  2. palapaweb怎样开启服务_为什么说微服务,要从前后端分离开始?一文带你揭秘深入微服务...

    前言 既要低头赶路,又要抬头望天,科技是为人服务的,任何技术背后都有更深层次的考量. 之前的文章中咱们聊了很多微服务的相关内容,简而言之,微服务的本质,就是一种可以加速分工.促进合作的新协作机制.知其 ...

  3. 从前后端分离到前后端整合的“退步”(一)项目结构

    系列文章目录 从前后端分离到前后端整合的"退步"(一)项目结构 从前后端分离到前后端整合的"退步"(二)pom.xml文件配置 Spring Boot + Vu ...

  4. 从前后端分离到前后端整合的“退步”(二)pom.xml文件配置

    系列文章目录 从前后端分离到前后端整合的"退步"(一)项目结构 从前后端分离到前后端整合的"退步"(二)pom.xml文件配置 Spring Boot + Vu ...

  5. 从巨石应用到微服务应用,从ESB到APIGateway,从前后端分离到中台出现,九九归一,Rest要一统天下?

    本文系作者本人原创,如需转载,请务必写明出处,谢谢! 题目很长,想说的东西很多. 一 IT的进化论 达尔文的进化论同样适用于IT世界,能大行其道的IT技术,确实是优胜劣汰,自然的选择. 有人说J2EE ...

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

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

  7. js array formdata_携程机票Node.js开发实践

    Nodejs自从2009年被开发出来以后,至今已经走过了9个年头,目前最新的稳定版已经到了10.13.从问世以后,Nodejs就深受前端工程师的喜欢. 在携程内部,Nodejs也是应用广泛,从开发工具 ...

  8. 干货 | 携程 SOA 的 Service Mesh 架构落地

    作者简介 本文作者 Dozer.Bender.vio-lin 来自携程 SOA 团队.目前主要负责 SOA 系统的研发工作和 Service Mesh 架构的演进.落地工作,同时也关注服务治理.JVM ...

  9. 明道云前后端分离这条路

    前后端分离是目前项目开发上主流的一种模式,这个概念已经流传很长时间,在新项目开发中要实现前后端分离并没有特别的难度,但在老项目中真正要实现前后端分离却不是一朝一夕的事情,特别是在经过时间洗礼的项目中, ...

最新文章

  1. Office 365 系列之一:初识Office 365
  2. 一文带你彻底了解Java异步
  3. JavaScript大杂烩9 - 理解BOM
  4. php insert into values 可以是数组吗,PHP INSERT INTO插入不了数据有关问题
  5. oracle 创建用户、授权、表空间
  6. 如何解决 linux socket TIME_WAIT 过多造成的问题(SYN、ACK、FIN、MSL、RST含义)netstat查看TCP连接数命令
  7. 18.虚拟机linux上网问题
  8. Flickr 的开发者的 Web 应用优化技巧(转)
  9. how is sales pipeline retrieved from backend
  10. linux命令chown和chmod什么区别
  11. Saving Beans HDU - 3037(卢卡斯定理)
  12. python123循环结构_来学Python啦,大话循环结构~
  13. python中列表实现去重使用_Python实现嵌套列表去重方法示例
  14. quartus管脚分配后需要保存吗_电脑磁盘显示未分配怎么办?磁盘数据如何恢复?...
  15. c语言1234为什么不是常量,C语言学习1
  16. Nginx+FastCGI+Python
  17. 【CSS基础笔记】——盒模型、块级元素、行内元素、浮动、对齐、定位
  18. 彻底理解SVD奇异值分解(singular value decomposition)
  19. 设计图纸管理系统办公系统实现无纸化
  20. 小米MIUI12开发版内测-答题

热门文章

  1. java Class类与反射
  2. 你知道数据中心宕机的真正成本吗?
  3. Rushcrm:客户关系管理适合的才是好的
  4. 嵌入式开发之davinci--- 8148/8168/8127 中的图像缩放sclr、swms之后出现图像视频卡顿、屏幕跳跃的问题...
  5. Exchange Server 2013之CAS服务器NLB负载均衡
  6. HTML5 利用canvas API 展示阴影效果
  7. python猜数字游戏编程、最后显示猜了几次_用Python完成猜数字游戏
  8. python 获取网络图片的大小
  9. 网站模糊测试爆破工具Wfuzz
  10. Kail Linux渗透测试教程之免杀Payload生成工具Veil