跳至主要内容

Mock → 真實 API 漸進切換

app-web 支援從 Mock API 漸進式切換到真實 API,確保開發過程中系統始終可運作。

設計理念

階段說明適用情境
Phase 1全部使用 Mock API前端開發初期、後端尚未就緒
Phase 2混合模式後端逐步完成,逐模組切換
Phase 3全部使用真實 API生產環境部署

MSW 控制機制

MSW (Mock Service Worker) 透過 config.app.msw.enabled 控制,根據 Vite 環境自動判斷。

配置方式

src/conf/config.ts
export const config: AppEnvironConfig = {
app: {
name: 'App',
version: '1.0.0',
stage: import.meta.env.MODE,
basename: '/',
baseURL: '/',
msw: {
enabled: import.meta.env.DEV, // 開發環境自動啟用
},
},
// ...
}

環境判斷

環境import.meta.env.DEVMSW 預設狀態說明
開發環境(npm run devtrue啟用自動攔截 API 請求
生產環境(npm run buildfalse關閉所有請求直接發送到後端

生產環境覆蓋(測試用)

在特殊情況下(如 E2E 測試),可透過後端 /config endpoint 在生產環境啟用 MSW:

// GET /config 回應
{
"app": {
"msw": {
"enabled": true
}
}
}

MSW 跨域攔截機制

問題背景

在混合模式(Phase 2)下,前後端可能運行在不同的 origin:

環境app-webapp-server
本地開發http://localhost:3000http://localhost:8080/app-server
SIT 環境http://localhost:3000https://sitapp.leandev.io/app-server

apiClient.baseURL 設定為跨域 URL 時,傳統的相對路徑 MSW handler 無法攔截:

// ❌ 相對路徑 handler 無法攔截跨域請求
const API_BASE = '/api/v1';
http.post(`${API_BASE}/auth/login`, handler);

// 請求:http://localhost:8080/app-server/api/v1/auth/login
// Handler:/api/v1/auth/login
// 結果:無法匹配!

萬用字元解決方案

所有 MSW handlers 使用萬用字元 * 匹配任意 origin:

src/mocks/handlers/auth.ts
// ✅ 萬用字元匹配任意 origin
const API_BASE = '*/api/v1';

export const authHandlers = [
http.post(`${API_BASE}/auth/login`, handler),
http.get(`${API_BASE}/auth/me`, handler),
];

匹配行為

萬用字元 * 只影響 origin 部分,路徑匹配依然精確:

Handler: */api/v1/auth/login

✅ /api/v1/auth/login (同源)
✅ http://localhost:8080/app-server/api/v1/auth/login (本地後端)
✅ https://sitapp.leandev.io/app-server/api/v1/auth/login(遠端環境)

❌ /api/v1/orders (路徑不同)
❌ /api/v2/auth/login (版本不同)

設計優勢

優勢說明
零額外配置不需要 Vite Proxy 或環境變數
環境無關無論 baseURL 設定為何,都能正確攔截
精確匹配萬用字元只影響 origin,路徑依然精確
簡化切換混合模式下,只需移除 handler 即可切換到真實 API

攔截流程圖

三階段切換流程

Phase 1:全部使用 Mock API

適用於前端開發初期,後端尚未就緒。

┌─────────────────────────────────────────────────┐
│ app-web + MSW │
│ │
│ npm run dev │
│ → MSW 自動啟用 │
│ → 所有 API 請求由 MSW handlers 處理 │
└─────────────────────────────────────────────────┘

開發指令

cd app-web
npm run dev

驗證 MSW 啟動

開啟瀏覽器 DevTools Console,應看到:

[MSW] Mock Service Worker started
[MSW] Available endpoints:
- POST /api/v1/auth/login
- GET /api/v1/auth/me
- GET /api/v1/products
- GET /api/v1/orders
- GET /api/v1/customers

Phase 2:混合模式

後端逐步完成 API 實作,前端逐模組切換到真實 API。

┌─────────────────────────────────────────────────┐
│ app-web + 混合模式 │
│ │
│ 認證 API → 真實(app-server 已實作) │
│ 訂單 API → 真實(app-server 已實作) │
│ 客戶 API → Mock(app-server 尚未實作) │
│ │
│ MSW 設定 onUnhandledRequest: 'bypass' │
│ → 未匹配的請求自動轉發到真實後端 │
└─────────────────────────────────────────────────┘

關鍵配置

src/App.tsx
await worker.start({
onUnhandledRequest: 'bypass', // 未匹配的請求繼續通過到真實伺服器
})

切換方式

移除對應的 MSW handler,該 API 就會自動轉發到真實後端。

例如,當 app-server 完成認證 API 後:

src/mocks/handlers/index.ts
import { authHandlers } from './auth'      // 移除此行
import { orderHandlers } from './orders' // 移除此行
import { customerHandlers } from './customers'

export const handlers = [
// ...authHandlers, // 註解或移除:使用真實 API
// ...orderHandlers, // 註解或移除:使用真實 API
...customerHandlers, // 保留:繼續使用 Mock
]

Phase 3:全部使用真實 API

所有後端 API 就緒,準備生產部署。

生產環境必要模組

生產環境部署需要完整架構:

  • app-web:前端 SPA
  • app-server:後端 RESTful API
  • app-web-host:將 SPA 封裝成 WAR 部署到 Java Application Server
┌─────────────────────────────────────────────────┐
│ app-web + app-server + app-web-host │
│ │
│ npm run build → 產出靜態資源 │
│ → 複製到 app-web-host │
│ → 打包成 WAR 部署 │
│ → 所有 API 連接 app-server │
└─────────────────────────────────────────────────┘

部署指令

cd app-web
npm run build

# 建置產出複製到 app-web-host
cd ../app-web-host
./gradlew build
# 產出:build/libs/app-web-host.war

開發環境設定

同時啟動前後端

開發時可同時啟動 app-web 和 app-server:

# Terminal 1:啟動後端
cd app-server
./gradlew bootRun

# Terminal 2:啟動前端
cd app-web
npm run dev

配置後端 URL

透過環境配置指定後端位置。MSW 萬用字元設計讓你無需額外的 Vite Proxy 配置:

src/conf/config.ts
export const config: AppEnvironConfig = {
app: {
// 本地後端
baseURL: 'http://localhost:8080/app-server',
// 或遠端環境
// baseURL: 'https://sitapp.leandev.io/app-server',
msw: {
enabled: true, // 混合模式:MSW + 真實後端
},
},
// ...
}
為什麼不需要 Vite Proxy?

由於 MSW handlers 使用萬用字元 */api/v1,無論 baseURL 設定為何,MSW 都能正確攔截。未匹配的請求會直接 bypass 到 baseURL 指定的後端,不需要額外的 proxy 層。

混合模式開發流程

┌─────────────────────────────────────────────────────────────┐
│ 混合模式開發 │
│ │
│ 1. 設定 baseURL 指向後端(本地或遠端) │
│ 2. 保持 msw.enabled = true │
│ 3. 移除已完成的 handler → 請求自動轉發到真實後端 │
│ 4. 保留未完成的 handler → 繼續使用 Mock │
└─────────────────────────────────────────────────────────────┘

相關文檔