前言
網頁程式其實是由前端程式和後端程式兩者所組成。傳統的網頁程式,會將兩者合併在同一個專案中。隨著網頁技術的進展,我們可以把前端程式和後端程式拆至兩個專案中,兩者使用不同的技術來實作。
在本文中,我們會說明這個架構,並探討為什麼要 (或不要) 使用此架構。
前後端分離的專案架構
即然採用前後端分離了,前端程式和後端程式自然會放在不同的專案中。這時候前端和後端可以採用不同的技術。
現階段來說,前端程式最好採用 Node.js 生態圈的開發工具。這是因為 Node.js 生態圈和網頁開發相關的套件相當完整,只要建置 Node.js 運行環境,就可以使用這些套件,不需再花時間建置其他語言的運行環境。
使用 Node.js 開發套件和開發 Node.js 網頁程式是無關的。我們只是要藉由一些 Node.js 套件輔助我們寫網頁前端程式而已。至於是否要用 Node.js 來寫網頁後端,反而是看後端框架的技術選項而定。
比起網頁前端,網頁後端程式的選項就自由得多。大部分主流的語言都有至少一種網頁程式函式庫或框架可用,語言的選擇反而不是重點。既然語言上沒有限制,應該要以靜態型別語言為優先選項,這不僅是效能上的考量,靜態型別語言在錯誤檢查上也更為完整。
是否要為了 JavaScript 刻意使用 Node.js 呢?筆者認為這不應該是考量的點,而且 JavaScript 本身在工程性上沒有特別優秀。Node.js 網頁程式的優勢在於撰寫高共時性的網頁程式,但在 Golang 等語言出現後,這項優勢就慢慢降低了。
前後端分離的主機規畫
由於我們採用前後端分離的架構,前端和後端視為兩隻獨立的程式,沒有必要放在同一台主機上,可以視其特性掛在不同主機上。
前端程式在本質上只是靜態網頁,所以用相對便宜的靜態網站主機即可。在前端程式中複雜的動態 UI 增修會發生在使用者的終端裝置上,而不是在網站主機上處理。在前端網頁程式中,網站主機的角色很單純,只是要把第一次存取網址時的頁面傳送到終端裝置而已。
由於實際的程式邏輯和運算會放在後端程式上,後端程式建議放在比較好的網站主機上。像是可以利用雲端運算 (cloud computing) 的特性來調節後端程式的運算資源使用量,用多少算多少,比較不會有硬體閒置所造成的折舊。
前後端分離的網域規畫
至於前後端程式要放在同網域或不同網域?其實要看自己的規畫。一般來說,使用不同網域比較易於規畫,像是:
https://example.com/
:主網站的網域https://api.example.com/
:後端程式的網域
如果要在同網域,則可參考以下規畫:
https://example.com/api/
:後端程式的網域https://example.com/*
:主網站的網域,需排除後端程式的網域
我們可以使用 Apache、Nginx 等網頁伺服器當代理者 (proxy),將不同網址指向不同的網頁程式。
同網域或不同網域主要的考量應該在於是否要支援舊瀏覽器。因舊瀏覽器在跨網域存取上會有限制,得用同網域方式來規畫。
前後端網頁程式如何溝通?
通訊方式
前端程式和後端程式是兩個獨立的程式,在兩者之間要有傳遞資料的方式。常見的有以下數種:
REST 直接使用 HTTP 協定來傳輸資料,資料通常會包成 JSON 格式,並且壓縮,以節省頻寬。除了 JSON 外,也可以用其他的檔案格式。REST 是目前網頁程式傳輸資料的標準做法。
相對來說,gRPC 效率會比 REST 好,但 gRPC 仍在發展中,支援沒那麼普遍。目前要在前端程式中用 gRPC 和後端程式溝通的話,要用第三方函式庫,像是 grpc-web。後端程式要用 gRPC 也要網頁函式庫或框架有支援才行。比起 REST,gRPC 會比較省運算資源,若專案可支援的話,可以考慮使用。
GraphQL 是由 Facebook (臉書) 所發展的新興資料查詢語言,有多種程式語言的 binding。GraphQL 主要的好處在於可檢查查詢 (query) 的型別,並依需求回傳所需的資料。以網頁程式來說,需要使用現代瀏覽器並搭配相關的函式庫才能使用。
跨網域資源分享
原本資源不能跨網域分享,這是著眼於安全性。為了處理這個議題,常見的處理方式有以下兩種:
- JSONP
- CORS
JSONP 算是舊方法,只能用 GET 請求傳遞資料,限制很多。CORS 則是目前的主流手法,除非目標瀏覽器不支援 CORS,才需考慮用 JSONP 傳資料,或是將兩隻程式放在同網域。
後端程式如何寫?
在前後端分離的架構下,後端程式和 UI 無關。後端程式只負責資料傳遞和程式運算。所以,後端技術的選擇相當自由,只要符合專案需求的技術皆可考慮。
在寫後端程式時,我們將網址視為程式的 API,即網頁 API (web API)。藉由 JSON 等語言中立格式在前後端間傳遞資料。此外,後端程式也做為網頁和資料庫等第三方程式的溝通橋樑。
前端程式如何寫?
在這個架構下,前端程式的角色比以前吃重。除了原本前端程式的工作外,前端程式還得負責協調程式的狀態和 UI 的變化。由於 JavaScript 可用來動態生成或修改網頁元素,因而可用來動態調整 UI。現在的前端程式不刷新頁面,而是藉由大量 Ajax 呼叫局部更新頁面。
根據程式的撰寫模式,可分為兩種方式:
- 直接操作網頁元素
- jQuery
- 原生 JavaScript
- 利用前端框架處理 UI 和資料間的連動
- Angular
- React
- Vue
- 其他前端框架
傳統的網頁程式直接操作網頁元素,寫起來比較直覺,但要自行處理 UI 和介面間的連動。相對來說,使用前端框架可以補足 UI 和資料間的連動議題,但一開始要花一些時間適應框架的使用方式。此外,新興前端框架對 IE 等舊瀏覽器支援不一定那麼好。
為什麼要前後端分離?
從程式碼的觀點來看,前後端分離是較好的架構。當前端程式獨立在後端程式之外時,我們就不用受限於後端程式的模板語言。日後因需求要更動後端所用的技術時,只要 web API 相符、程式行為相符,就可以把後端程式抽換掉,不需重寫 UI 的部分。
以系統的觀點來看,當前後端分離後,我們可以更容易地調節網站主機的花費。根據前端程式和後端程式各自的特性,將兩隻程式分別部署在不同類型的主機上,把錢用在刀口上。
由於前後端程式分開在兩個專案上,更有利於團隊分工。前端工程師完全不需要碰觸後端程式,就可以自已啟動專案程式。後端工程師也是如此。由於兩隻程式是分離的,使用版本控制軟體時不會相互干擾。
為什麼不前後端分離?
前後端分離的架構會使得專案的複雜度上升。並不是所有的專案都適合或需要使用這種架構。
如果專案要支援舊瀏覽器,許多前後端分離所需的特性將無法使用,若堅持使用前後端分離只是徒增專案的難度。這時候回頭使用傳統的單一網頁程式專案或許是比較好的選擇。
對於以內容為主體的網站,使用前後端分離就顯得有點多餘。此外,現在有許多內容管理系統,像是 WordPress,可以不寫程式碼就做出網站。內容型網站還得寫網頁程式的機會其實沒那麼大,除非要客製一些現有的內容管理系統無法滿足的需求。
典型的前後端分離架構,所有的 UI 都是在客戶端生成,這項行為對 SEO (搜尋引擎優化) 是不利的。即使 Google 的爬蟲很聰明,能處理由 JavaScript 動態生成的頁面,這種架構對 SEO 仍有一些影響。目前的變通方式是透過 dynamic rendering 等方式,預先生成一些內容讓搜尋引擎的爬蟲去爬內容。
結語
在本文中,我們介紹了前後端分離的專案架構,如何處理各種相關的議題,以及其優缺點。雖然這種架構在起始時要多一點前置工作,長期來說會使得專案更易於維護。除非專案的情境不適用於前後端分離,應該要儘量地使用這種架構來增進專案的品質。