無需CORS,用nginx解決跨域問題,輕鬆實現低程式碼開發的前後端分離

2022-07-15 18:04:32

近年來,前後端分離已經成為中大型軟體專案開發的最佳實踐。

在技術層面,前後端分離指在同一個Web系統中,前端伺服器和後端伺服器採用不同的技術棧,利用標準的WebAPI完成協同工作。這種前後端分離的"混合開發"模式下,前後端通常會部署到不同的伺服器上,即便部署在同一臺機器,因為宿主程式(如後端用Tomcat,前端用nginx)不同,埠號也很難統一。

(圖片來源網路)

這意味著位於A域(如https://foo:80/website) 的頁面,需要呼叫B域的WebAPI(如https://bar:8080/webservice),這是一個典型的跨域存取,瀏覽器預設會判定該操作有安全風險。如果不進行處理,則會拒絕這次WebAPI呼叫,提示對應的錯誤。

(跨域請求導致的錯誤)

現在如何該怎麼解決跨域的問題呢?目前有4個主流技術方案:

JSONP

如果你需要處理的請求只有GET,可以考慮JSONP。

JSONP的原理就是利用<script>標籤沒有跨域限制的特點,通過<script>標籤src屬性,傳送帶有callback引數的GET請求,伺服器端將介面返回資料拼湊到callback函數中,返回給瀏覽器,瀏覽器解析執行,從而前端拿到callback函數返回的資料。


(JSONP的呼叫流程)

這種做法很常規,但是你需要為前端提供JSONP的響應,其他終端呼叫時提供不帶JSONP的響應,因此會帶來額外的開發和測試工作量。

iFrame

通常情況下,前後端分離帶來的跨域存取都侷限在同一個主域的不同子域(如a.foo.com和b.foo.com)之間。所以,你可以利用iFrame載入位於被呼叫WebAPI所在域的頁面,然後將兩個頁面的document.domain設定為主域名(如foo.com),就通過iFrame中的子頁面請求WebAPI了。

(圖片來源網路)

這種做法比較麻煩,我們需要為WebAPI配套開發起中轉作用的頁面,但對於開發者而言依舊有很大的開發工作量。

CORS

和前兩種方案相比,CORS(跨域資源共用)是一個"一勞永逸"的方案。

我們不需要為每個WebAPI做額外的處理,而是需要在後端程式啟動時,增加一些處理工作。主流的後端服務都有處理CORS的類庫,這裡就不再做展開介紹了。

這個方案的核心原理,是在發起正式的請求前,先傳送一個OPTIONS謂詞的HTTP請求,詢問發起請求的頁面是否有呼叫該域服務的許可權;如果後端說OK,瀏覽器就繼續請求,否則提示錯誤。

使用這種方案的開發工作量小,如果直接使用成熟類庫的話,開發和測試的工作量甚至可以忽略不計。不過,因為每個跨域的請求都會觸發一次往外的OPTIONS請求,對伺服器會造成額外的開銷和壓力。

反向代理

反向代理機制,把前端的A域和後端的B域合併成一個C域,從根本上解決跨域問題。

這個方案僅需設定,對前後端的程式沒有侵入;同時內網中的反向代理通常也不會帶來額外的效能開銷。


(圖片來源網路)

總體來說在編碼開發的時代,上述四種方案都有適用的應用場景,各有優缺點。進入低程式碼開發時代後,前後端分離的應用面更廣,如使用JavaScript編碼開發前端、配合低程式碼構建的後端,或使用Java編碼開發後端,供低程式碼構建的前端呼叫。

(低程式碼時代的前後端分離,來自 低程式碼沙龍)

低程式碼開發的核心價值在於節省開發投入,提升開發效率,所以,方案1(JSONP)和方案2(iFrame)已經很少被用到低程式碼混合開發領域。相比於方案3(CORS),方案4(反向代理)因為效能開銷較小,應用場景會更多一些。

下面,我們將以活字格+nginx為例,介紹利用nginx解決跨域問題,實現前後端分離的具體做法。

(反向代理的架構示意圖)

利用nginx解決跨域問題

  1. 開始設定之前,我們使用活字格開發兩個應用,僅包含前端頁面的frontend和包含後端WebAPI(伺服器端命令)的backend,並將其分別釋出到物理機或雲主機上,應用的埠設定為8081和8080。我們可以通過以下地址存取這兩個應用:
  1. 安裝nginx,並在組態檔/conf/nginx.conf中HTTP節點設定前後端的伺服器,即upstream節點:

upstream backend {

server host\_name:8080;

}

upstream frontend {

server host\_name\_2:8081;

}

  1. 在HTTP節點下的server節點,設定監聽埠和轉發策略,這樣就可以將http://host_name:8080/backend對映為http://proxy_name:8000/backend ,http://host_name_2:8081/frontend 對映為http://proxy_name:8000/frontend

listen 8000;

server\_name proxy\_name;

location /frontend {

proxy\_pass http://frontend/frontend ;

}

location /backend {

proxy\_pass http://backend/backend ;

}

  1. 上述操作後,使用者存取的域名統一成了http://proxy_name:8000,跨域問題解決了。但是,不要著急。活字格預設會啟用Http Referer驗證機制,不允許跨域呼叫內建服務。所以,你還需要開啟前端應用所在的伺服器端的管理控制檯http://host_name_2:22345/UserService/ManagementPage/WebSecurity

在HTTP Referrer允許列表中新增nginx代理伺服器的地址(也就是使用者實際使用的地址,記得在後面加一個*號適配)。

  1. 設定完成後,你可以就可以在前端頁面中通過【傳送HTTP請求命令】,呼叫後端的WebAPI了。


(在前端呼叫後端WebAPI並彈窗顯示返回結果)

特別提示:如果你需要將前端、後端和nginx部署在同一臺機器上,可以將上述proxy_name、host_name、host_name_2統一替換為你的機器名或IP地址。

作為一款強大的反向代理和Web伺服器,nginx的用途非常廣泛,本文僅僅使用到了它的反向代理功能。除此之外對於負載均衡的解決nginx也有很優秀的表現,在後續內容中我們會為大家做更加深入的介紹。

如需詳細瞭解如何使用低程式碼開發前後端分離的企業級應用,快速轉型全棧工程師,可以檢視:

https://gcdn.grapecity.com.cn/forum.php?mod=viewthread&tid=146511&extra=page%3D1%26filter%3Dtypeid%26typeid%3D272

除此之外如果你對更多低程式碼行業現狀與發展趨勢感興趣可以檢視:

https://help.grapecity.com.cn/pages/viewpage.action?pageId=67969931