從前後端分離到GraphQL,攜程如何用Node實現?\n
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的使用場景,使其發揮更大的價值。
更多內容,請關注前端之巔。
相關文章
- 從MVC到前後端分離MVC後端
- 遷移iOS API到前端並實現前後端分離(非Node.js)iOSAPI前端後端Node.js
- 圖解基於 Node.js 實現前後端分離圖解Node.js後端
- 實現前後端分離的心得後端
- node-vue前後端分離記錄Vue後端
- 從部署上做到前後端分離後端
- 前後端分離,最佳實踐後端
- 前後端分離實踐有感後端
- 前後端分離與Node和NPM的那些事後端NPM
- centos7.9 配置nginx實現前後端分離CentOSNginx後端
- NCF 如何通過WebApi實現前後端分離WebAPI後端
- 從邏輯解偶到物理解耦再到前後端分離解耦後端
- 實踐中的前後端分離後端
- 一步步從後端渲染到前後端分離經驗分享(1)後端
- Django+Vue.js搭建前後端分離專案 web前後端分離專案實踐DjangoVue.js後端Web
- 前後端分離專案實踐分析後端
- 再談前後端分離後端
- 前後端分離那些事後端
- 淺談前後端分離後端
- 前後端分離——使用OSS後端
- 基於 Node.js 前後端分離的一點思考Node.js後端
- 通過nginx部署前端程式碼實現前後端分離Nginx前端後端
- 前後端分離 Vue + NodeJS(Koa) + MongoDB,從產品到開發,全棧實踐後端VueNodeJSMongoDB全棧
- 前後端分離後的前端時代後端前端
- 前後端分離後模組開發後端
- 前後端不分離到分離演變,優勢,前後端介面聯調,排錯及優化後端優化
- 為什麼前後端分離了,你比從前更痛苦?後端
- 前後端分離的思考與實踐(三)後端
- 前後端分離的思考與實踐(四)後端
- 前後端分離的思考與實踐(五)後端
- 前後端分離的思考與實踐(六)後端
- ???前後端分離模式的思考???後端模式
- 前後端分離——資料mock後端Mock
- vue前後端分離修改webpackVue後端Web
- 前後端分離整合SpringSecurity後端SpringGse
- 淺談WEB前後端分離Web後端
- 什麼是前後端分離?後端
- 前後端分離Ajax入門後端