Vite 反向代理跨網域取得登入權限

Lastor
Code 隨筆放置場
6 min readJul 2, 2023

情境說明

前端要對後端發出 API request,可分為「同網域」以及「不同網域」。大多情況下,不同網域時會使用 JWT 來做登入與授權,同網域會用 cookie-session 的方式居多。

有一種情境是,前端專案是分離的、完全不同的 repo,但是上 Server 時會跟後端是同一個 domain。然而登入頁可能並不是在同個前端站點做的。

這時如果是用 cookie-session 的授權方式,就會發生在 localhost 開發時,網域與主站點不一樣,導致登入權限帶不過去的問題,也就無法在本機開發時打 API 了。

# 開發環境
http://localhost:3000 # 主站, 會在這登入
http://localhost:4000 # 子站, 前端拆分專案

# 正式環境
https://www.mysite.com # 主站
https://www.mysite.com/site2 # 子站

以前時不時會碰到這樣的情況,當時我能想到的解法有兩個,一個是本機開發全用假資料做,不測串接了,做好後直接丟到 Server 上確認。另一個是本機臨時修改後端的 code,把登入驗證那段給屏蔽掉。

但就是很麻煩,而且這樣可以說是 localhost 根本無法 work。

解法思路

最近又碰到類似情形,想說這樣不是個辦法,就問了一下認識的老後端前輩,結果得到一個有趣的 idea,那就是去模擬正式環境,直接起 Nginx 或 Apache 去做反向代理,在 localhost 把主站跟子站串到同一個網域下。

# 開發環境
http://localhost:3000 # 主站
http://localhost:4000 # 子站

# 代理 Server
http://localhost:5000 # 代理介接主站
http://localhost:5000/site2 # 代理介接子站

順著這個思路,就想說 Node.js 應該也可以用 Express + http-proxy 來做。那如果 Node.js 可以做,理論上 vite 與 webpack dev server 本身的 proxy 功能也能行?!

打包工具的 dev server proxy 功能,大多會用來處理 CORS 問題。如果不清楚如何用反向代理處理 CORS,可以參考這一篇:

期望的 Server 代理結構大概長這樣:

# 主站
http://localhost:3000

# vite dev server
http://localhost:4000 # 代理介接主站
http://localhost:4000/site2 # 子站

試了一下,還真的可以,雖然連線速度會稍微慢上一些,但完全是可行的。而且 vite 的代理設定也相當容易。

設定 Vite 反向代理

  1. 設定 base URL

將開發時的 base URL 也設定成跟正式環境一樣。

export default defineConfig({
base: '/site2/',
// ...
})

這樣 dev 啟動時,vite 就會提示你需要連到該 path。

# vite 預設 port 為 5173
http://localhost:5173/site2

2. 設定反向代理

export default defineConfig({
base: '/site2/',
server: {
port: 4000, // 按需求設定, 也可直接用預設的 5173
proxy: {
// 反向代理所有非 "/site2" 開頭的請求
'^(?!\/site2).*': {
// 代理目標, 如果要連線上的測試站點也行
target: 'http://localhost:3000',
// 收到 redirect 命令時, 自動覆寫 host 與 port
autoRewrite: true,
protocolRewrite: 'http',
// 覆寫 origin 標頭
changeOrigin: true,
}
},
},
})

proxy 屬性是一個 object,下面的 key 直接寫你要代理的 path。例如單純處理 CORS 時,可能會這樣寫:

proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
},
}

這就表示,所有往 http://localhost:4000/api 這個位置發的請求,都會被轉發到 target 設定的目標 http://localhost:3000/api

而這邊是要將所有非 base URL,也就是 /site2/ 以外的所有請求,都轉發到主站上,這可以用正規表達式處理。不會寫就直接問 chatGPT,他就會給你這段正規。

/^(?!\/site2).*/

changeOrigin 跟跨 CORS 一樣,也是要開的,不然代理回來還是會撞 CORS。

剩下的兩個覆寫設定 autoRewriteprotocolRewrite 是用來處理重新導向的。例如,通常登入之後,可能後端會直接發一個 redirect 命令,把你導回首頁之類。

如果啥都不設定的話,那就會原封不動的拿到主站發出的重新導向,然後會被導回去。

# 假設原本在代理端點登入
http://localhost:4000/signin

# Server 發出 redirect, 就被直接轉過去了
http://localhost:3000/account

autoRewrite 設定為 true 之後,就會自動將 redirect 的 host 與 port 覆寫成跟代理端點一樣,這樣就能保持在代理 Server 的 domain 上。

protocolRewrite 則是定義要不要改 ssl 協定。例如你可能想直接代理到後端架好的測試站,甚至是正式站上。線上的站點可能是 https 的,那 redirect 命令就會被轉成 https,所以需要覆寫回 http

完成這些設定之後,就可以直接在 vite server 同時連線主站跟子站,並進行登入,以 vite server 的 domain 取得登入授權了。

之後前端要發 API request,就跟正式環境一樣,直接往同網域的 vite 站點發就可以了。例如:

GET /api/products

總結一下,直接利用 vite / webpack 這些打包工具提供的 proxy 功能,不用多費力氣去裝 Nginx / Apache 甚或是 docker 之類的任何東西。僅需要用前端熟悉的工具鍊,就能解決這問題!!

並且這不需要額外修改專案外的任何網路設定,只要一開始在專案寫好,git commit 上去。團隊裡的任何人,都只要 pnpm dev (npm run dev)就能直接 work 了哦。

--

--

Lastor
Code 隨筆放置場

Web Frontend / 3D Modeling / Game and Animation. 設計本科生,前遊戲業 3D Artist,專擅日本動畫與遊戲相關領域。現在轉職為前端工程師,以專業遊戲美術的角度涉足 Web 前端開發。