大咖直播-鸿蒙原生开发与智能提效实战!>>> 了解详情
写点什么

从前后端分离到 GraphQL,携程如何用 Node 实现?

  • 2019-01-23
  • 本文字数:3488 字

    阅读完需:约 11 分钟

从前后端分离到GraphQL,携程如何用Node实现?

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 的使用场景,使其发挥更大的价值。


更多内容,请关注前端之巅。



2019-01-23 10:289605

评论

发布
暂无评论
发现更多内容

讲师征集令 | Apache DolphinScheduler Meetup分享嘉宾,期待你的议题和声音!

白鲸开源

Apache 大数据 开源 workflow dolpinsheduler

NFT质押LP流动性挖矿系统开发详情

开发微hkkf5566

OpenHarmony—内核对象事件之源码详解

OpenHarmony开发者

Open Harmony

Geoffrey Hinton:我的五十年深度学习生涯与研究心法

OneFlow

人工智能 机器学习 深度学习

云上竞技,360°见证速度与激情

天翼云开发者社区

直播预告|大咖共话:汽车行业数字化转型趋势与对策

3DCAT实时渲染

使用 Open Connector 进行 HubSpot 和 SAP 系统的集成工作

汪子熙

云原生 系统集成 SAP 6月月更 open-connector

字节跳动数据平台技术揭秘:基于ClickHouse的复杂查询实现与优化

字节跳动数据平台

Clickhouse

Web3.0时代来了,看天翼云存储资源盘活系统如何赋能新基建(上)

天翼云开发者社区

区块链 Web

后端开发—10个小技巧教你保证线程安全

C++后台开发

线程 多线程 后端开发 linux开发 C++开发

征文投稿丨使用轻量应用服务器搭建博客环境

阿里云弹性计算

MySQL nginx 博客 Node 轻量应用服务器

使用Karmada实现Helm应用的跨集群部署

华为云开发者联盟

云原生 后端

CRM 全栈开发工具 WebClient UI Workbench 的设计细节介绍

汪子熙

CRM webUI SAP 全栈开发 6月月更

高并发、高可用、弹性扩展,天翼云护航企业云上业务

天翼云开发者社区

云计算 服务器

有哪些好用的供应商管理系统

优秀

低代码 数字化转型 供应商管理

大型体育赛事与犯罪风险

清林情报分析师

数据分析 警务技术 警务安全 风险分析 犯罪预防

wallys/DR7915-wifi6-MT7915-MT7975-2T2R-support-OpenWRT-802.11AX-supporting-MiniPCIe-Module

wallys-wifi6

3. Caller 服务调用 - dapr

MASA技术团队

C# .net 框架 Framework dapr

Wallys/4×4 MU-MIMO 6GHz QCN9074 Single Band Wireless Module

wallys-wifi6

疫情之下,元宇宙游戏开发设计如何发展?

开源直播系统源码

游戏开发 元宇宙

CODING DevOps 助力中化信息打造新一代研效平台,驱动“线上中化”新未来

CODING DevOps

持续集成 CODING DevOps 项目协同 合作 中化信息

中能融合携手天翼云打造“能源大脑”

天翼云开发者社区

云计算 大数据 安全

AI落地的新范式,就“藏”在下一场软件基础设施的重大升级里

九章云极DataCanvas

天翼云Web应用防火墙(边缘云版)通过首批可信认证

天翼云开发者社区

代理类型升级,APISIX 支持 Kafka 作为上游

API7.ai 技术团队

kafka 后端 代理 网关 APISIX 网关

openGauss内核:SQL解析过程分析

华为云开发者联盟

数据库 sql 后端

跟着官方文档学 Python 之:解释器和IDE

甜甜的白桃

Python pycharm IDLE 6月月更

ShardingSphere-Proxy 前端协议问题排查方法及案例

SphereEx

数据库 ShardingSphere

中国SSD行业企业势力全景图

ToB行业头条

Curve 替换 Ceph 在网易云音乐的实践

网易数帆

分布式 云原生 存储 Ceph curve

浅谈 SAP 软件里的价格折扣设计原理

汪子熙

SAP ERP pricing 企业管理软件 6月月更

从前后端分离到GraphQL,携程如何用Node实现?
_大前端_付文平_InfoQ精选文章