劉紅衛(wèi)
(泰達(dá)圖書館檔案館 天津 300457)
如今移動互聯(lián)網(wǎng)高速發(fā)展,多種終端訪問對Web應(yīng)用開發(fā)提出了更高的要求。用戶需求不斷變化,Web應(yīng)用能夠自適應(yīng)不同類型終端,不再單純滿足傳統(tǒng)瀏覽器端的體驗。用戶需求的變化提高了Web開發(fā)難度,而針對不同終端開發(fā)不同版本應(yīng)用的解決方法,并不是有效的開發(fā)方式,不僅需要額外的開發(fā)人員,還會帶來成本增加、開發(fā)時間拖長等影響[1]。前后端分離是多終端 Web應(yīng)用開發(fā)的可行方案,將后端保持不變,前端根據(jù)用戶的需求和體驗要求進(jìn)行多終端定制開發(fā),這樣只需要改變前端代碼,后端保持不變或微調(diào),即可滿足用戶多終端需求,節(jié)省開發(fā)時間,降低開發(fā)成本,提高開發(fā)效率。
綜上所述,Web應(yīng)用開發(fā)的前后端分離模式是大勢所趨。
傳承歷史文明,服務(wù)現(xiàn)代化的物質(zhì)文明和精神文明建設(shè),搜集、整理和保存地方文獻(xiàn),歷來都是公共圖書館的基本任務(wù)之一[2]。地方文獻(xiàn)具有鮮明的區(qū)域性和實用性特點,在公共圖書館評估工作中,對地方文獻(xiàn)的館藏建設(shè)、開發(fā)利用都提出了相關(guān)要求,并占有較高分值。
筆者所在的圖書館在幾年前建立了地方文獻(xiàn)系統(tǒng),并將擁有版權(quán)許可的文獻(xiàn)進(jìn)行數(shù)字化,讀者可以在線檢索、閱讀,獲得地方文獻(xiàn)排架信息,文獻(xiàn)類型包括書、報、刊、照片、圖片以及音視頻等。該系統(tǒng)是由第三方開發(fā),運行在 Windows Server系統(tǒng)下采用Asp.net開發(fā),已運行多年,現(xiàn)在經(jīng)常出現(xiàn)系統(tǒng)死機(jī)狀態(tài),需要重啟服務(wù)器才能恢復(fù)服務(wù),讀者意見很大。由于該系統(tǒng)是早期產(chǎn)品,廠商不再提供支持,當(dāng)時的開發(fā)人員已經(jīng)跳槽,現(xiàn)在無人能解決這個問題。
為了徹底解決系統(tǒng)中存在的上述問題,我們仔細(xì)研究了軟件目錄和結(jié)構(gòu),確定地方文獻(xiàn)的對象數(shù)據(jù)文件存于一定規(guī)則的目錄中,并且保存完整,元數(shù)據(jù)保存在 KBase數(shù)據(jù)庫中,可以導(dǎo)出文本文件。于是,決定自行開發(fā)一套新的地方文獻(xiàn)系統(tǒng),既能實現(xiàn)舊系統(tǒng)的所有功能,又能實現(xiàn)響應(yīng)式設(shè)計在多終端上使用??紤]到用戶將來對多終端界面需求的變化以及開發(fā)人員少的現(xiàn)狀,新系統(tǒng)的開發(fā)模式?jīng)Q定采用前后端分離模式。
2.1.1 軟件開發(fā)平臺的選擇
Node.js基于 Chrome V8引擎的 JavaScript運行,使用高效、輕量級的事件驅(qū)動、非阻塞 I/O模型,它的包生態(tài)系統(tǒng) npm是目前世界上最大的開源庫生態(tài)系統(tǒng)[3]。Node.js使JavaScript不僅可以應(yīng)用在瀏覽器端,也可以運行在服務(wù)器端。目前,Node.js憑借其優(yōu)秀的性能受到全球各大公司的重視,如 eBay、Microsoft、PayPal、Uber、Yahoo 等,國內(nèi)阿里巴巴、百度、騰訊等也在很多項目中應(yīng)用,可見 Node.js的發(fā)展已經(jīng)成熟,它能快速創(chuàng)建大規(guī)模的網(wǎng)絡(luò)應(yīng)用,處理高吞吐量的實時連接。Node.js有 Windows、Linux、macOS、SunOS、AIX 等系統(tǒng)平臺版本,具有良好的跨平臺可移植性,可以在Windows上開發(fā),然后部署到Linux等其他系統(tǒng)上。
圖書館能承擔(dān)系統(tǒng)開發(fā)的人員很少,平日開發(fā)工作基本局限于頁面程序的改寫和功能提升上,大家都對 JavaScript腳本語言比較熟悉。針對此情況,結(jié)合Node.js可用于全棧開發(fā)及諸多特性和優(yōu)點,在前后端分離系統(tǒng)的開發(fā)管理方面也比較方便,為此選擇了Node.js為軟件開發(fā)平臺。
2.1.2 前后端分離系統(tǒng)設(shè)計
如圖1所示,在地方文獻(xiàn)系統(tǒng)前后端分離架構(gòu)設(shè)計中,前后端分別運行在不同的Node.js創(chuàng)建的Web Server上,前端負(fù)責(zé)接收用戶的請求、相關(guān)驗證和數(shù)據(jù)展示效果,后端負(fù)責(zé)按照約定好的 API請求處理業(yè)務(wù)邏輯、訪問數(shù)據(jù)庫、處理數(shù)據(jù),并按約定的數(shù)據(jù)格式向前端返回相關(guān)數(shù)據(jù)(JSON格式),包括請求API的時候進(jìn)行相關(guān)驗證。前后端之間通過HTTP請求進(jìn)行交互,前端獲取數(shù)據(jù)后,對頁面進(jìn)行組裝和渲染,并將最終生成的頁面返回瀏覽器。
圖1 圖書館地方文獻(xiàn)系統(tǒng)前后端分離架構(gòu)圖Fig.1 Back-and-rear separation architecture of the local library documentation system
其前端采用 MVVM(Model-View-View Model)模式,它是在 MVC(Model-View-Controller)模式基礎(chǔ)上改進(jìn)的開發(fā)模式,它與MVC模式相同的是把視圖和數(shù)據(jù)分離,不同的是引入 ViewModel替換掉Controller來完成視圖和數(shù)據(jù)的雙向綁定,通過自動的方式完成大部分?jǐn)?shù)據(jù)處理工作,從而降低了前端開發(fā)的復(fù)雜度。
在進(jìn)行前后端分別開發(fā)之前,需要商定好前后端交互所需的 API,包括通訊接口、驗證策略以及數(shù)據(jù)格式等,形成文檔,確定文檔版本號。前后端開發(fā)人員要共同遵守此文檔,需要修改時要共同確認(rèn),變更文檔和文檔版本號,然后按照文檔中的接口規(guī)范進(jìn)行前后端的并行開發(fā)。
地方文獻(xiàn)系統(tǒng)的前后端通訊是通過 HTTP請求作為API接口,這些API當(dāng)然可以隨意制定,只要前后端開發(fā)人員達(dá)成一致即可。但隨意的 API形式缺乏合理性,可讀性差存在較多隱患。因此,我們采用目前較為流行的RESTful制定了API接口。
REST(Representational State Transfer)描述了一個架構(gòu)樣式的網(wǎng)絡(luò)系統(tǒng),比如 Web應(yīng)用程序。在目前主流的 3種 Web服務(wù)交互方案中,REST相比于SOAP和 XML-RPC更加簡單明了,無論是對 URL的處理還是對 Payload的編碼,REST都傾向于用更加簡單輕量的方法設(shè)計和實現(xiàn)。值得注意的是 REST并沒有一個明確的標(biāo)準(zhǔn),而更像是一種設(shè)計風(fēng)格。每個資源都使用 URI(Universal Resource Identifier)得到一個唯一的地址,所有資源都共享統(tǒng)一的接口,以便在客戶端和服務(wù)器之間傳輸狀態(tài),使用的是標(biāo)準(zhǔn)的HTTP 方法,比如 GET、PUT、POST 和 DELETE[4]。符合這種風(fēng)格的 Web應(yīng)用則稱為 RESTful。使用RESTful制定的API很容易理解,可避免產(chǎn)生歧義。
2.3.1 前端的實現(xiàn)
前端頁面采用目前流行框架 Vue.js,它是基于MVVM 模式的輕量級響應(yīng)式框架,它能有效簡化Web前端開發(fā)流程。Vue.js與其他重量級框架不同之處是,它是一套構(gòu)建用戶界面的漸進(jìn)式框架,采用自底向上增量開發(fā)的設(shè)計方式,是更加靈活、開放的解決方案,架構(gòu)更加簡單,適合開發(fā)人員快速掌握其全部特性并投入使用,還便于與第三方庫或既有項目整合[5]。
Vue.js體量輕盈、性能優(yōu)異、路由功能強(qiáng)大,而且易用、靈活、高效,在 npmjs.com 上有 vue.js腳手架工具vue-cli,通過vue-cli能直接生成Node.js環(huán)境下的 Vue應(yīng)用程序框架,減少構(gòu)建時間。另外 vue.js現(xiàn)在應(yīng)用廣泛,網(wǎng)絡(luò)交流社區(qū)很多,使用中如遇到任何問題都可以利用這些資源及時找到解決辦法,保證開發(fā)工作的順利進(jìn)行。
為了適應(yīng)多終端用戶瀏覽器環(huán)境,頁面采用響應(yīng)式布局設(shè)計,根據(jù)終端環(huán)境的不同,自動適應(yīng)屏幕大小,優(yōu)化頁面顯示。響應(yīng)式布局框架有很多,比較流行的是 bootstrip.js,圖書館的開發(fā)人員在以前的項目中也曾使用過,使用 npm 可以輕松地將 bootstrap.js加入到開發(fā)環(huán)境中,然后用 import語句將 bootstrap及相關(guān) css文件引入到程序文件中,bootstrap和 vue整合使用效果非常好。
前端的Web Server是由vue-cli工具生成vue開發(fā)框架中所包含的,它實際是一個 express框架。前端向后端請求 HTTP API異步操作時會出現(xiàn)跨越問題,可以通過在前端 Web server程序中引入 httpproxy-middleware中間件來解決。
前端程序通過 mock.js按照約定的接口文檔生成模擬數(shù)據(jù)進(jìn)行單獨測試,不用等后端 API接口開發(fā)完畢,這樣能夠在前后端的集成測試前發(fā)現(xiàn)大部分問題,從而節(jié)省集成測試的時間,縮短開發(fā)周期。
2.3.2 后端的實現(xiàn)
后端 Web Server采用 Koa2。Koa是由 Express原班人馬打造的,致力于成為一個更小、更富有表現(xiàn)力、更健壯的 Web框架。使用 Koa編寫 web應(yīng)用,通過組合不同的generator,可以免除重復(fù)繁瑣的回調(diào)函數(shù)嵌套,并極大地提升錯誤處理的效率。Koa不在內(nèi)核方法中綁定任何中間件,它僅僅提供了一個輕量優(yōu)雅的函數(shù)庫,使得編寫Web應(yīng)用變得得心應(yīng)手[6]。Koa2是一個簡單的MVC架構(gòu),結(jié)構(gòu)非常清晰,地方文獻(xiàn)系統(tǒng)的數(shù)據(jù)庫采用mysql,通過npm將mysql訪問包文件加入到后臺開發(fā)環(huán)境中,將數(shù)據(jù)處理程序如mysql數(shù)據(jù)庫的操作、本地文件訪問等程序放到models目錄,將業(yè)務(wù)邏輯處理程序放到controllers目錄,另外將API接口定義在router目錄中api.js文件內(nèi),該文件要引入 koa-router包,在主程序中通過語句app.use(require('./server/routes/ api.js').routes())啟動API接口路由。
Koa2中Koa Context將node的request和response對象封裝到單個對象中,為編寫 Web應(yīng)用程序和API提供了許多有用的方法。比如用ctx標(biāo)識符創(chuàng)建一個 Context,使用語句 ctx.body=result_set,這里的result_set是指API接口處理程序的結(jié)果數(shù)據(jù)集,這樣前端就獲得了后端返回的數(shù)據(jù)。
應(yīng)用Koa2開發(fā)是非常簡單、快捷、清晰的,要實現(xiàn) Koa功能擴(kuò)展既可以自己編寫中間件程序,也可在 npmjs.com網(wǎng)站上找那些優(yōu)秀的支持 Koa2的中間件直接使用,提高開發(fā)效率。但是,網(wǎng)上的中間件良莠不齊,需要仔細(xì)甄別。
前后端分離的地方文獻(xiàn)系統(tǒng)集成測試完畢后,可以部署到一臺或多臺服務(wù)器,前后端分開以及數(shù)據(jù)庫獨立,可根據(jù)業(yè)務(wù)運行的實際情況按需部署,應(yīng)用非常靈活。
目前,圖書館的地方文獻(xiàn)系統(tǒng)前后端和數(shù)據(jù)庫暫時部署在一臺 Windows Server上,從運行的效果看已經(jīng)滿足讀者的訪問要求。這得益于部署時使用了Node.js的高級生產(chǎn)進(jìn)程管理工具PM2。
Node.js以單線程的方式運行,多核心處理器系統(tǒng)不能發(fā)揮最大的性能。Node.js提供了 cluster模塊,可以生成多個工作線程,只需要將代碼封裝到cluster的處理邏輯中,再增加額外的代碼用于解決一個線程掛掉的問題。PM2內(nèi)置 cluster模式包含了所有上述的處理邏輯,不必修改任何代碼,輕松地實現(xiàn)負(fù)載均衡,并能實時進(jìn)行擴(kuò)展。
PM2簡化了很多 Node.js應(yīng)用管理中的繁瑣任務(wù),不論什么情況都能保持生產(chǎn)進(jìn)程一直運行,生產(chǎn)環(huán)境實現(xiàn)零停機(jī)更新。它還提供了性能監(jiān)控、自動重啟、控制臺檢測、遠(yuǎn)程控制接口API等功能,目前PM2支持在Linux、macOS、Windows等多平臺運行。
通過 Node.js進(jìn)行前后端分離的地方文獻(xiàn)系統(tǒng)開發(fā)的優(yōu)勢為:首先,前后端開發(fā)人員的職責(zé)完全分清,能夠同時并行開發(fā)和測試,互不干擾,提高了開發(fā)效率,縮短了開發(fā)時間,降低了項目成本;其次,前端界面變化后端無需修改,可以輕松應(yīng)對今后多終端需求的改變,降低了維護(hù)成本;最后,提高了代碼的可復(fù)用性和可維護(hù)性,架構(gòu)明確,代碼清晰。
利用Node.js開發(fā)前后端分離的圖書館地方文獻(xiàn)系統(tǒng)的實踐,不僅僅是前后端開發(fā)的分工,也是開發(fā)環(huán)境、代碼、部署的完全分離,與傳統(tǒng)的 Web應(yīng)用開發(fā)模式相比,提高了開發(fā)效率,增強(qiáng)了代碼的可維護(hù)性,提高了系統(tǒng)的可用性、伸縮性、擴(kuò)展性。今后還應(yīng)在接口服務(wù)化、代碼模塊化、功能組件化等方面進(jìn)一步探索,以便應(yīng)對越來越復(fù)雜的 Web應(yīng)用開發(fā)挑戰(zhàn)。