跳至主要内容

如何切換 Mock 到真實 API

本指南說明如何從開發環境的 Mock API 切換到連接真實後端。

前置條件

  • 已完成基於 Mock API 的開發
  • 後端 API 已部署並可存取

方法一:環境變數切換

步驟 1:設定環境變數

# .env.development(Mock API)
VITE_USE_MOCK=true
VITE_API_BASE_URL=

# .env.staging(真實 API)
VITE_USE_MOCK=false
VITE_API_BASE_URL=https://api-staging.example.com

# .env.production(生產 API)
VITE_USE_MOCK=false
VITE_API_BASE_URL=https://api.example.com

步驟 2:條件啟動 MSW

// src/main.tsx
async function enableMocking() {
if (import.meta.env.VITE_USE_MOCK === 'true') {
const { worker } = await import('./mocks/browser');
return worker.start({
onUnhandledRequest: 'bypass',
});
}
}

enableMocking().then(() => {
createRoot(document.getElementById('root')!).render(<App />);
});

步驟 3:啟動不同環境

# 使用 Mock API
npm run dev

# 連接 Staging API
npm run dev -- --mode staging

# 連接生產 API(本地測試)
npm run dev -- --mode production

方法二:漸進式切換

一次切換一個 API,降低風險。

步驟 1:在 Handler 中添加旁路

// src/mocks/handlers/products.ts
import { http, passthrough } from 'msw';

const USE_REAL_API = import.meta.env.VITE_REAL_PRODUCT_API === 'true';

export const productHandlers = [
http.get('/api/v1/products', () => {
if (USE_REAL_API) {
return passthrough(); // 轉發到真實 API
}
// Mock 回應
return HttpResponse.json(mockProducts);
}),
];

步驟 2:逐一啟用

# .env.development
VITE_REAL_PRODUCT_API=true # 商品用真實 API
VITE_REAL_ORDER_API=false # 訂單仍用 Mock
VITE_REAL_CUSTOMER_API=false # 客戶仍用 Mock

方法三:完全移除 MSW

生產環境可完全移除 MSW。

步驟 1:條件載入

// src/main.tsx
async function bootstrap() {
// 只在開發環境載入 MSW
if (import.meta.env.DEV && import.meta.env.VITE_USE_MOCK !== 'false') {
const { worker } = await import('./mocks/browser');
await worker.start({ onUnhandledRequest: 'bypass' });
}

createRoot(document.getElementById('root')!).render(<App />);
}

bootstrap();

步驟 2:排除打包

// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
external: import.meta.env.PROD ? ['msw'] : [],
},
},
});

常見問題

API 路徑不一致

Mock 和真實 API 路徑可能不同,使用 axios 攔截器處理:

// src/services/api.ts
const api = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || '',
});

// 路徑轉換
api.interceptors.request.use((config) => {
if (import.meta.env.VITE_USE_MOCK !== 'true') {
// 真實 API 使用 /api/v1 前綴
config.url = `/api/v1${config.url}`;
}
return config;
});

認證機制不同

Mock 使用簡化的 JWT,真實 API 可能有不同機制:

// src/services/auth.ts
export const authService = {
login: async (credentials) => {
if (import.meta.env.VITE_USE_MOCK === 'true') {
// Mock 登入
return api.post('/auth/login', credentials);
}
// 真實 OAuth2 流程
return oauthLogin(credentials);
},
};

資料格式差異

使用轉換層統一資料格式:

// src/services/transformers/product.ts
export function transformProduct(raw: any): Product {
return {
id: raw.id || raw.productId,
name: raw.name || raw.productName,
price: Number(raw.price),
// ...
};
}

驗證清單

切換前確認:

  • 所有 API 端點都有對應的真實 API
  • 認證流程已測試
  • 錯誤處理已更新
  • 資料格式轉換已完成
  • CORS 設定正確

下一步