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