web-app 本機 API proxy
這份文件回答什麼
這份文件說明 web-app 本機開發時,如何只讓指定 API path 走本機 API server,其它 API 照常走 staging。
這不是 API mapping 文件,也不是後端路由文件;要查 endpoint 本身的業務意義,請回到API 路由與遷移或 API detail 文件。
使用情境
本機跑前端:
make dev預設 API 會打:
https://api-staging.pro360.com.tw如果只想讓部分 API 改打本機後端,例如:
http://127.0.0.1:12351就使用本機 API proxy。
白話概念
這套機制分成兩段:
瀏覽器前端 JavaScript
先把指定 staging API URL 改成本機同源 path
webpack dev server,也就是 Node
再把這個本機同源 path 轉送到本機 API server例如原本前端要打:
https://api-staging.pro360.com.tw/quote_categories/auto_complete/清潔/consumer.json如果這個 path 有被加進 proxy 清單,瀏覽器端會先改成:
/quote_categories/auto_complete/清潔/consumer.json所以 Chrome Network 看到的 Request URL 會變成:
http://127.0.0.1:3000/quote_categories/auto_complete/清潔/consumer.json接著 webpack dev server 再把它轉送到:
http://127.0.0.1:12351/quote_categories/auto_complete/清潔/consumer.json這樣做的目的,是讓瀏覽器以為 request 是打同一個來源 127.0.0.1:3000,避免 CORS 問題;真正打到本機 API server 的動作交給 webpack dev server 處理。
流程圖
使用者打開 http://127.0.0.1:3000
|
v
public/index.html
|
| 先載入
v
/local-api-proxy-runtime.js
|
| 攔截點 1:很早載入的外部 script
| 攔截 window.fetch / XMLHttpRequest.open
v
webkit-staging-latest.js
|
| 如果它打 staging API,會先被改成 /xxx
v
前端 app bundle 載入
|
v
index.js
|
| installLocalApiProxyRewrite()
v
modules/utils/local-api-proxy.js
|
| 攔截點 2:前端 app 裡的 fetch / XMLHttpRequest
| 把指定 staging API 改成同源 path
v
APIManager 發 API
modules/utils/api-manager.js
|
| 攔截點 3:APIManager 裡的 fetch 包一層
| rewriteLocalApiProxyUrl(url)
v
原本:
https://api-staging.pro360.com.tw/quote_categories/auto_complete/清潔/consumer.json
改成:
/quote_categories/auto_complete/清潔/consumer.json
|
v
瀏覽器實際送出:
http://127.0.0.1:3000/quote_categories/auto_complete/清潔/consumer.json
|
v
webpack dev server
webpack.config.js
|
| proxy 設定
v
實際轉送到:
http://127.0.0.1:12351/quote_categories/auto_complete/清潔/consumer.json攔截點在哪裡
攔截點 1:外部 webkit script 載入前
位置:
/Users/mattsu/Documents/Site/web-app/public/index.html
/Users/mattsu/Documents/Site/web-app/webpack.config.jspublic/index.html 先載入:
<script src="/local-api-proxy-runtime.js"></script>然後才載入外部 webkit script。
/local-api-proxy-runtime.js 是由 webpack.config.js 在本機開發時產生的。它會先改寫:
window.fetch
window.XMLHttpRequest.prototype.open這是為了處理 React app 還沒啟動前,外部 script 就先發 API 的情況。
攔截點 2:React app 啟動後
位置:
/Users/mattsu/Documents/Site/web-app/index.js
/Users/mattsu/Documents/Site/web-app/modules/utils/local-api-proxy.jsindex.js 會執行:
installLocalApiProxyRewrite();這段是跑在瀏覽器,不是 Node。它同樣會改寫瀏覽器裡的:
window.fetch
window.XMLHttpRequest.prototype.open攔截點 3:APIManager 裡的 fetch
位置:
/Users/mattsu/Documents/Site/web-app/modules/utils/api-manager.jsAPIManager 裡的 fetch 會先經過:
rewriteLocalApiProxyUrl(url)這是保險的一層。只要 APIManager 用這個 fetch 發 API,URL 就會先被檢查一次。
誰跑在瀏覽器,誰跑在 Node
跑在瀏覽器:
index.js
modules/utils/local-api-proxy.js
modules/utils/api-manager.js
public/index.html 載入的 /local-api-proxy-runtime.js
跑在 Node:
webpack.config.js
webpack dev server proxy啟動方式
cd /Users/mattsu/Documents/Site/web-app
LOCAL_API_PROXY=http://127.0.0.1:12351 make dev沒有帶 LOCAL_API_PROXY 時:
make dev會維持原本行為,API 照常打 staging。
新增或移除 proxy API
只改這個檔案:
/Users/mattsu/Documents/Site/web-app/config/local-api-proxy.js格式:
const LOCAL_API_PROXY_ENV = 'LOCAL_API_PROXY';
const localApiProxyPaths = [];
module.exports = {
LOCAL_API_PROXY_ENV,
localApiProxyPaths,
};新增
把 API path 前綴加進 localApiProxyPaths:
const localApiProxyPaths = [
'/quote_categories/auto_complete',
'/users/validate_user.json',
'/new/v1/something',
];移除
從 localApiProxyPaths 刪掉該 path:
const localApiProxyPaths = [
'/quote_categories/auto_complete',
];如果清單是空的:
const localApiProxyPaths = [];即使有帶 LOCAL_API_PROXY,也不會有 API 被轉到本機。
path 規則
清單放的是「API path 前綴」,不是完整 URL。
例如放:
'/quote_categories/auto_complete'會套用到:
/quote_categories/auto_complete/清潔/consumer.json
/quote_categories/auto_complete//consumer.json不會影響其它 API。
Network 怎麼看
成功時,Chrome DevTools Network 會看到 request 變成同源:
http://127.0.0.1:3000/quote_categories/auto_complete/清潔/consumer.json實際上會由 webpack dev server proxy 到:
http://127.0.0.1:12351/quote_categories/auto_complete/清潔/consumer.json如果 Network 還看到:
https://api-staging.pro360.com.tw/quote_categories/auto_complete/...先確認:
- 是否用
LOCAL_API_PROXY=http://127.0.0.1:12351 make dev啟動。 - 是否已 hard reload,或 DevTools 是否勾選 Disable cache。
- 該 path 是否已加到
config/local-api-proxy.js。
目前預設
config/local-api-proxy.js 預設不代理任何 API:
const localApiProxyPaths = [];需要時再把 path 加進去。