前後端分離:分離開發,一體發佈

前後端分離開發實踐了很久了,前兩天需要把一個項目上線,準備 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/

然後各組領任務,項目技術負責人開始創建項目文件,編寫開發規範……


喜歡此文,點個贊 ⇙

支持作者,賞個咖啡豆 ⇓

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章