refactor: ky

This commit is contained in:
skytek_xinliang
2026-05-07 11:17:30 +08:00
parent 87fbc1dda8
commit 71683482e1
15 changed files with 146 additions and 360 deletions
+20 -8
View File
@@ -1,24 +1,24 @@
# Services
`src/services` 是資料存取與 HTTP 邊界,負責封裝 axios client、interceptor、token/session、錯誤處理與 API 模組。
`src/services` 是資料存取與 HTTP 邊界,負責封裝 ky client、hooks、token/session、錯誤處理與 API 模組。
## 目前資料流
```txt
component/view -> store/composable -> service module -> httpClient -> interceptor
component/view -> store/composable -> service module -> httpClient -> hooks
```
原則:
- component 不直接處理底層 HTTP client、token、interceptor 或錯誤正規化。
- component 不直接處理底層 HTTP client、token、hooks 或錯誤正規化。
- store 或 composable 負責協調 UI 狀態與呼叫 service。
- service 回傳資料,不持有 UI 狀態。
- service 不 import component、view 或 store。
## 目前檔案
- `client.ts`:建立單一 axios instance,設定 `baseURL`、timeout、credentials 與 interceptor
- `interceptors.ts`:集中處理 request token 注入與 response 錯誤。
- `client.ts`:建立單一 ky instance,設定 `prefix`、timeout、credentials 與 hooks
- `interceptors.ts`:集中提供 ky hooks處理 request token 注入與 response 錯誤。
- `error.ts`:提供 `normalizeError()` 與統一錯誤型別。
- `http-error.ts`:提供全域 HTTP 錯誤事件。
- `http-toast.ts`:提供 HTTP 錯誤提示相關流程。
@@ -38,6 +38,18 @@ API module 應:
- 定義與該 module 相關的 request/response 型別。
- 接收 `AbortSignal` 等 request option,但不管理頁面 loading 或 controller 狀態。
## ky 使用注意事項
本專案使用 ky,不使用 axios。新增或調整 API module 時注意:
- ky 不回傳 axios 的 `{ data, status, headers }` 物件。需要 JSON 時使用 `.json<T>()`
- 若呼叫端已經依賴 `{ data }` 形狀,請在 API module 內包回 `{ data: await ... }`,不要讓 store 或 component 混用多種 response 形狀。
- ky 的錯誤型別是 `HTTPError``TimeoutError` 等,不是 `AxiosError`。錯誤一律交給 `normalizeError()`,呼叫端不要直接判斷 ky error。
- ky 基於 Fetch API,取消請求使用原生 `AbortController``signal`
- token 注入、401 force logout、HTTP 錯誤導頁與 toast 都集中在 ky hooks。不要在單一 service module 裡重複實作。
- FormData 請用 `body: formData`JSON payload 請用 `json: payload`
- 如果需求需要 upload progress、request/response transform、或其他 axios 專屬行為,先確認 ky/fetch 是否有等價做法,再決定是否擴充 service layer。
## HTTP Client 設定
`client.ts``baseURL` 優先使用 `VITE_API_BASE_URL`,否則使用 `/service/api`。開發模式下,Vite proxy 會將 `/service/*` 轉送到後端。
@@ -64,10 +76,10 @@ production 不應沿用 template 內的示範後端位址,應由使用專案
token 由 `tokenService` 作為單一來源:
- store 負責登入成功後寫入 token,以及登出時清除 token。
- interceptor 只讀取 token 並附加到 request。
- 401 或 HTTP 錯誤由 interceptor 與錯誤事件流程集中處理。
- hooks 只讀取 token 並附加到 request。
- 401 或 HTTP 錯誤由 hooks 與錯誤事件流程集中處理。
錯誤透過 `normalizeError()` 轉成 UI 可理解的格式。UI 或 store 不需要直接理解 AxiosError。
錯誤透過 `normalizeError()` 轉成 UI 可理解的格式。UI 或 store 不需要直接理解 ky 的 HTTPError。
## 請求取消