前後端分離開發實踐了很久了,前兩天需要把一個項目上線,準備 SSL 證書時發現,居然需要申請 3 個證書(1 年期免費的證書只能對單個子域名申請),這 3 個域名是:
- sys.project.cn,Web 應用前端
- api.project.cn,應用後端 RESTful API
- m.project.cn,移動端
屁大點個項目,需要搞得這麼複雜?用子路徑不行嗎?就像這樣:
- //sys.project.cn/
- //sys.project.cn/api/
- //sys.project.cn/m
回答我說,不行!因爲是前後端分離方式開發的,每一項都是單獨的項目,單獨發佈出來,只能分別作爲網站發佈……我那感覺,就像喝了兩瓶二鍋頭,不僅醉了,而且上頭,就差發酒瘋了!
且不說是不是一定要分離發佈的問題,就算各自獨立發佈,至少有三種方案可以發佈成子路徑:
- 虛擬目錄或純靜態的子目錄
- IIS 站點上“添加應用程序”
- 使用 Nginx 反向代理
但這不是重點,重點是:
分離開發就一定得分離發佈嗎
自從應用前後端分離開發模式以來,分工明確,合作愉快。最近後端一般是用 NET Core 開發,前端使用的 Vue 技術棧。如果偶爾後端人力不足,有點數據庫基礎的前端工程師還可以拿 Node.js 幫着實現一部分後端需求。移動端的 Android 團隊已經精簡得只剩下一個人了,只需要維護一個框架應用,處理點硬件調用,把移動端頁面往裏一套就能解決問題。
各團隊已經習慣了分離開發,除了討論接口設計,其他時候團隊間交流最多的可能就是:“API 測試地址是啥,我需要聯調一下。”所以各團隊也習慣了自己發佈,公佈地址給其他團隊測試、聯調。久而久之,居然形成了分離開發就得分離發佈的印象。
對於較大型一些的項目來說,分離發佈可能是必要的:純靜態的前端部分可以發佈到 CDN,後端部分可以發佈到多個服務器上外加一層負載均衡。但是對於使用人數不過幾百人,併發最多幾十人的小型應用來說,就一臺應用服務器,把所有東西揉吧揉吧,放一起就能當作一體式開發的 Web 應用發佈出來,真沒必要去分離。
就上面的例子來說,除了應用後端需要跑程序,需要 NET Core Runtime,另外兩項全是純靜態。然而,
A: 另外兩項不是靜態的,因爲要通過構建生成!
B: 什麼構建?
A: Vue 框架寫的,需要通過npm run build
構建了才能發佈。
B: 那麼,構建結果是不是純靜態的?
A: 構建結果應該不是純靜態的吧,需要在 IIS 上建站點發布。
B: 那麼,構建結果直接用瀏覽器可以打開嗎?不用 IIS,只用靜態 http-server 可以部署嗎?
A: 好像可以
B: 那就是純靜態!
這是一個插曲,不過這得強調一下,“構建”這一過程的結果,不一定就非得是動態的 Web 應用。我們已經在前端工程化上實踐了這麼久,應該瞭解:前端工程化之後,構建的結果是靜態的,不需要在服務器上跑程序,只需要服務器按 URL 提供靜態資源。
分析下後端應用的發佈內容
現在來看一下後端發佈的結果(部分)
.../api_publish
|-- wwwroot/
`-- *.dll
程序中,所有 API 都是通過路由中間件解析 URL 之後轉發到各 Controller 的。假如發佈後綁定了域名 api.project.cn
,那麼:
//api.project.cn/
打開的是項目模板提供的一個默認頁面,這個頁面在wwwroot
中 —— 對了,wwwroot
就是這個 Web 應用的靜態資源目錄//api.project.cn/api/...
這個子路徑下提供全套 Web API 服務
因爲應用後端目前只提供 Web API 服務,wwwroot
裏只不過放了一些沒用的靜態資源 —— 都是創建項目時模板提供的靜態資源,完全可以刪得一個不剩。wwwroot
中的內容刪乾淨之後,訪問 http://api.project.cn/
會得到一個 404,但沒關係,因爲 API 完好!
那麼,如果把 wwwroot
裏放上前端構建的結果呢?
看看前端項目結構
.../project_root
|-- src/ <-- 源文件
|-- dist/ <-- 構建結構(發佈目錄)
| |-- index.html <-- 入口頁面
| |-- assets/ <-- 資源(圖片等)
| `-- *.js;*.js.map <-- 構建出來的 js 腳本等
|-- node_modules/ <-- npm 包緩存
`-- * <-- 項目配置、說明等
這個結構中,dist
目錄是 npm run build
構建出來的,這是一個發佈目錄,只有 dist
中的內容需要部署到 Web 服務器上。
揉一下子
現在把 dist
目錄放在後端發佈目錄 api_publish
中去,改名爲 wwwroot
,替換掉原來的 wwwroot
,Api 的發佈目錄就變成了這樣:
.../publish
|-- wwwroot/ <-- 前端構建結果:dist
| |-- index.html
| |-- assets/
| `-- *.js;*.js.map
`-- *.dll
這個目錄在 IIS 裏部署出來,直接訪問 //api.project.cn/
(之前綁定的域名),我們會毫無懸念地看到前端頁面出來了。由於前端頁面中 Ajax 調用的 Base URL 都是 //api.project.cn/
,所以 API 調用也沒有問題。
不過是 Web 應用的主頁一般不會通過 //api.project.cn/
來訪問,所以綁定 sys.project.cn
域名來訪問。//sys.project.cn/
沒有問題,可以打開頁面。之前綁定的 api.project.cn
並未取消,所以 Ajax 調用也沒有問題。
注:從
//sys.project.cn/
通過 Ajax 調用//api.project.cn/
可能會存在跨域問題,不過在這個案例中,跨域問題早就處理過了,不細說。
申請 SSL 證書
接下來,開始申請 SSL 證書。如果只申請一個證書(收費證書很貴的),是該申請 api.project.cn
的,還是 sys.project.cn
的?
不管 api.project.cn
還是 sys.project.cn
都可能在接收到的請求中包含敏感信息,也可能在響應中包含敏感數據。別的不說,Ajax 調用就已經涉及到了兩個部分的信息交換,任何一方不安全,整體都是不安全的。
但是隻有一個證書,就得放棄一個域名,放棄哪一個比較好?
sys.project.cn
是應用入口,應該告知用戶,而 api.project.cn
是在頁面中隱含調用的,所以應該放棄 api.project.cn
。而放棄 api.project.cn
,就意味着需要把 Web API 部署爲 sys.project.cn
的子路徑中,即 //sys.project.cn/api/
。然後把前端 Ajax 調用的 Base URL 改爲 //sys.project.cn/api/
即可。
這不,//sys.project.cn/
和 //sys.project.cn/api
就把前後端揉合在一起了,搞成一體式發佈。
再來個移動端
對了,還有一個針對移動端的前端靜態資源需要發佈,它和發佈應用前端原理一樣,但是得發佈到 .../wwwroot/m/
。問題是,需要以虛擬目錄的形式發佈嗎?
其實這個問題不是難題,純靜態的東西,怎麼揉都行。
一體式發佈
如果,三端不是同時發佈,而是各有各的生命週期,那最好發佈成三個目錄:
.../publish/api/
,部署爲 IIS 站點(刪除掉其中的 wwwroot 目錄).../publish/sys/
,做成符號鏈接(Windows 下用 Junction)到.../publish/api/wwwroot
.../publish/mobile/
,可以直接在 IIS 中部署成/m
虛擬目錄,也可以sys
那樣做成一個符號鏈接
對於多數小項目來說,三端都是同時發佈、聯合測試的。這種情況下,就可以使用一個構建腳本將前端 dist
、移動端 dist
和 Web API 發佈目錄拷貝到一起,按如下結構發佈:
.../publish/
|-- *.dll
`-- wwwroot/ <-- 前端構建結果:dist
|-- index.html
|-- assets/
|-- *.js;*.js.map
`-- m/ <-- 移動端構建結果:dist
|-- index.html
|-- assets/
`-- *.js;*.js.map
分離式開發
一體式發佈說完了,再回過頭來說說分離式開發。
因爲一開始的問題出現在部署的時候,所以我們反推了一體式發佈的過程。但實際上,應該反過來,按正常的順序,從項目開始開發的時候來規劃。
項目開始開發,說明它的需求已經確定下來。那麼,就基本上能確定用戶該怎麼來使用它,它應該怎樣部署。所以創建項目工作區的時候會想到這樣一個目錄結構:
.../project
|-- wwwroot/ <-- 前端靜態資源
| `-- m/ <-- 移動端靜態資源
|-- **/*.cs <-- 源代碼
`-- * <-- 項目及其他各種配置文件等
然後進行分工計劃:
- 前端一組寫
wwwroot
,但要把wwwroot/m
這個目錄保留給二組 - 前端二組寫
wwwroot/m
- 後端組寫
project
如果直接在整個工作區中協作複雜度會比較高,而且前端工程師看到後端代碼會頭痛,後端工程師看到前端代碼也頭痛。所以拆分項目,同時決定構建方法:
- 爲
wwwroot
創建一個前端項目web
,構建輸出到wwwroot
- 爲
wwwroot/m
創建另一個前端項目mobile
,構建輸出到wwwroot/m
project
從源文件中刪除wwwroot
,不關心前端過程- 構建方法:按如下順序整體構建
- 構建
project
,並整體發佈到.../publish/
- 構建
web
,得到.../web/dist
,將其拷貝到.../project/wwwroot/
- 構建
mobile
,得到.../mobile/dist
,拷貝到.../project/wwwroot/m/
- 構建
然後各組領任務,項目技術負責人開始創建項目文件,編寫開發規範……
喜歡此文,點個贊 ⇙
支持作者,賞個咖啡豆 ⇓