
前言
對於前端開發者來講 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: { '/foo': 'http://localhost:4567', '/api': { target: 'http://jsonplaceholder.typicode.com', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), }, '^/fallback/.*': { target: 'http://jsonplaceholder.typicode.com', changeOrigin: true, rewrite: (path) => path.replace(/^\/fallback/, ''), }, '/api': { target: 'http://jsonplaceholder.typicode.com', changeOrigin: true, configure: (proxy, options) => { } }, '/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 問題時,你還是要在後端伺服器上做處理,而不是在前端做處理。
參考文獻
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
Advertisement