Vite 中使用 Proxy 解決 CORS 問題

Image

前言

對於前端開發者來講 CORS 是非常常見的狀況,所以這一篇我就順便紀錄跟分享一下 Vite 如何使用 Proxy 解決 CORS 問題。

Vite Proxy

首先我們在 Vite 的官方文件中可以找到 Proxy 的相關設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
export default defineConfig({
server: {
proxy: {
// 字符串简写写法:http://localhost:5173/foo -> http://localhost:4567/foo
'/foo': 'http://localhost:4567',
// 带选项写法:http://localhost:5173/api/bar -> http://jsonplaceholder.typicode.com/bar
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
// 正则表达式写法:http://localhost:5173/fallback/ -> http://jsonplaceholder.typicode.com/
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, ''),
},
// 使用 proxy 实例
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
configure: (proxy, options) => {
// proxy 是 'http-proxy' 的实例
}
},
// 代理 websockets 或 socket.io 写法:ws://localhost:5173/socket.io -> ws://localhost:5174/socket.io
'/socket.io': {
target: 'ws://localhost:5174',
ws: true,
},
},
},
})

其實官方文件就已經將 Proxy 的使用方式寫得很清楚了,只需要依照官方文件的描述,加入到 vite.config.js 中就可以使用 Proxy 了,所以這一篇到這邊結束(哎?)

那為了方便閱讀,所以我還是稍微整理一下 Proxy 的使用方式。

純字串寫法

純字串寫法相對簡單跟單純,只需要將要代理的路徑跟目標路徑寫在一起就可以了。

1
2
3
4
5
6
7
export default defineConfig({
server: {
proxy: {
'/foo': 'https://api-example.com',
},
},
})

那麼當你運行專案時,你的 AJAX 通常可能會這樣寫

1
2
3
4
axios.get('/foo')
.then((res) => {
console.log(res);
})

那麼你在網頁上看到的請求會是 http://localhost:5173/foo,而實際上的請求會是 https://api-example.com/foo

選項寫法

選項寫法相對比較複雜一點,但你可以透過選項來調整你的代理設定。

1
2
3
4
5
6
7
8
9
10
11
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'https://api-example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
})

這邊我會一一介紹一下選項的屬性用途

  • target: 代理的目標地址
  • changeOrigin: 是否改變原始請求的 Host 頭
  • rewrite: 重寫路徑

這邊比較多的問題應該是 changeOrigin,這個選項主要是調整 origin,如果你的目標 API 有檢查 origin 的話,那麼你就需要將這個選項設為 true,否則發送請求時會被拒絕,這個選項的主要目的是改寫 header 中的 origin

rewrite 就是重寫路徑,這個選項的主要目的是將請求的路徑轉換成目標 API 的路徑,這邊我們可以看到我們將 /api 轉換成了空字串,所以當你在網頁上看到的請求會是 http://localhost:5173/api,而實際上的請求會是 https://api-example.com/

舉例來講,假設你的目標 API 是 https://api-example.com/foo,但你的 AJAX 卻這樣寫

1
2
3
4
axios.get('/api/foo')
.then((res) => {
console.log(res);
})

透過 rewrite 這個選項來重寫路徑的話,你在瀏覽器上雖然是看到 http://localhost:5173/api/foo,但實際上的請求會是 https://api-example.com/foo

正則表達式寫法

正規表達式寫法跟選項寫法很像,只是這種作法我自己也沒有用過,只是在官方文件中有提到,所以我就順便紀錄一下。

1
2
3
4
5
6
7
8
9
10
11
export default defineConfig({
server: {
proxy: {
'^/fallback/.*': {
target: 'https://api-example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, ''),
},
},
},
})

當發起請求時是 http://localhost:5173/fallback,那麼實際上的請求會是 https://api-example.com

Proxy 實例

接下來我要額外介紹一個東西,也就是 Proxy 實例,這個東西其實就是 http-proxy 的實例,你可以透過 configure 這個選項來調整 http-proxy 的設定,而它的寫法跟前面的寫法很像,只是多了一個 configure 選項。

1
2
3
4
5
6
7
8
9
10
11
12
13
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'https://api-example.com',
changeOrigin: true,
configure: (proxy, options) => {
...
}
},
},
},
})

那麼為什麼要特別提到 configure 呢?舉例來講,你是不是常常掛上 Proxy 之後,但還是請求失敗甚至是出現 404 的錯誤呢?這時候你可能會想說是不是自己掛 Proxy 的路徑請求有錯才會導致,但是你卻又不知道該怎麼看 Proxy 的請求紀錄,這時候你就可以透過 configure 這個選項來調整 http-proxy 的設定,讓你可以看到 Proxy 的請求紀錄。

你只需要改成以下這樣就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'https://api-example.com',
changeOrigin: true,
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, _res) => {
console.log('Sending Request to the Target:', options.target + proxyReq.path);
});
}
},
},
},
})

那麼當然不只有這些而已,你還可以看回傳跟錯誤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'https://api-example.com',
changeOrigin: true,
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, _res) => {
console.log('Sending Request to the Target:', req.method, options.target + proxyReq.path);
});

proxy.on('proxyRes', (proxyRes, req, res) => {
console.log('Receiving Response from the Target:', req.method, options.target + req.url);
});

proxy.on('error', (err, req, res) => {
console.log('Error Occurred:', err);
});
}
},
},
},
})

接下來你就可以在終端機看到 Proxy 的請求紀錄了

1
2
Sending Request to the Target: GET https://api-example.com/api
Receiving Response from the Target: GET https://api-example.com/api

其他更多的 Proxy 選項可以參考 http-proxy

常見問題

這邊也額外補充一個常見的問題,也就是 Proxy 只能用於開發環境,因此正式環境是無法運作的,除非你額外架設一個後端伺服器,但通常這樣子很沒必要,所以必須要先釐清一件事情,Proxy 只是方便開發者在開發環境下串接 API,而不是用來取代後端伺服器,因此當遇到 CORS 問題時,你還是要在後端伺服器上做處理,而不是在前端做處理。

參考文獻

Liker 讚賞

這篇文章如果對你有幫助,你可以花 30 秒登入 LikeCoin 並點擊下方拍手按鈕(最多五下)免費支持與牡蠣鼓勵我。
或者你可以也可以請我「喝一杯咖啡(Donate)」。

Buy Me A Coffee Buy Me A Coffee

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ