diff --git a/package.json b/package.json index e4d9823..3b2b71e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "module": "./dist/timi-web.mjs", "style": "./dist/timi-web.css", "private": false, - "version": "0.0.21", + "version": "0.0.22", "license": "MIT", "scripts": { "dev": "vite", diff --git a/src/store/device.ts b/src/store/deviceStore.ts similarity index 100% rename from src/store/device.ts rename to src/store/deviceStore.ts diff --git a/src/store/index.ts b/src/store/index.ts index bcd10e8..5026a79 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,2 +1,2 @@ -export * from "./device"; -export * from "./user"; +export * from "./deviceStore"; +export * from "./userStore"; diff --git a/src/store/user.ts b/src/store/userStore.ts similarity index 100% rename from src/store/user.ts rename to src/store/userStore.ts diff --git a/src/types/Model.ts b/src/types/Model.ts index 20941d3..ab28e74 100644 --- a/src/types/Model.ts +++ b/src/types/Model.ts @@ -13,7 +13,7 @@ export type Model = { deletedAt?: number; } -export type Response = { +export type ApiResponse = { code: number; msg?: string; data: T; diff --git a/src/utils/Network.ts b/src/utils/Network.ts index 12420fb..00c1646 100644 --- a/src/utils/Network.ts +++ b/src/utils/Network.ts @@ -1,75 +1,119 @@ -import axios, { InternalAxiosRequestConfig } from "axios"; -import Cooker from "./Cooker"; -import type { Response } from "../types/Model"; -import Time from "./Time"; -import { userStore } from "../store/user"; +import axios, {type AxiosInstance, type AxiosResponse, type InternalAxiosRequestConfig} from "axios"; +import {ApiResponse} from "../types"; -type ErrorCallback = (response: Response) => void; +export type ErrorCallback = (response: ApiResponse) => void; +export type RequestInterceptor = (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig; +export interface ResponseObserverPayload { + config?: InternalAxiosRequestConfig; + status?: number; + response?: AxiosResponse; + error?: any; + serverResponse?: ApiResponse; +} +export type ResponseObserver = (payload: ResponseObserverPayload) => void; let globalErrorCallback: ErrorCallback | null = null; +let globalRequestInterceptor: RequestInterceptor | null = null; +let globalResponseObserver: ResponseObserver | null = null; export const setGlobalErrorCallback = (callback: ErrorCallback) => { globalErrorCallback = callback; }; -const userTokenInterceptors = async (config: InternalAxiosRequestConfig) => { - let token = userStore.loginUser.token?.value; - const cookieToken = Cooker.get("Token"); - if (token && token === cookieToken) { - config.headers.set({"Token": token}); - } else { - if (cookieToken) { - token = cookieToken; - userStore.loginUser.token = { - value: token, - expireAt: Time.now() + Time.D - }; - } - if (token) { - await userStore.login4Token({ - value: token, - expireAt: Time.now() + Time.D - }); - } - } - return config; +export const setGlobalRequestInterceptor = (callback: RequestInterceptor | null) => { + globalRequestInterceptor = callback; }; -axios.defaults.withCredentials = true; -axios.interceptors.response.use((axiosResp: any) => { - if (!axiosResp.config.responseType) { - // 服务端返回 - const serverResp = axiosResp.data as Response; - if (serverResp.code < 40000) { - // 200 或 300 HTTP 状态段视为成功 - return serverResp.data; - } else { - if (globalErrorCallback) { - globalErrorCallback(serverResp); - } - // 由调用方处理 - return Promise.reject(serverResp.msg); - } + +export const setGlobalResponseObserver = (callback: ResponseObserver | null) => { + globalResponseObserver = callback; +}; + +const notifyResponseObserver = (payload: ResponseObserverPayload) => { + if (!globalResponseObserver) { + return; } - return axiosResp.data; -}, (error: any) => { - // 请求错误 - if (error) { - if (error.response && error.response.status) { - throw error; + globalResponseObserver(payload); +}; + +const applyDefaultInterceptors = (instance: AxiosInstance) => { + instance.defaults.withCredentials = true; + instance.interceptors.request.use((config) => { + if (globalRequestInterceptor) { + return globalRequestInterceptor(config); } - if (error.request) { - if (error.message.startsWith("timeout")) { - throw new Error("time out"); + return config; + }); + instance.interceptors.response.use((axiosResp: any) => { + if (!axiosResp.config.responseType) { + // 服务端返回 + const serverResp = axiosResp.data as ApiResponse; + if (serverResp.code < 40000) { + notifyResponseObserver({ + config: axiosResp?.config, + status: axiosResp?.status, + response: axiosResp, + serverResponse: serverResp + }); + // 200 或 300 HTTP 状态段视为成功 + return serverResp.data; } else { - throw new Error(error.message); + notifyResponseObserver({ + config: axiosResp?.config, + status: axiosResp?.status, + response: axiosResp, + serverResponse: serverResp, + error: serverResp.msg + }); + if (globalErrorCallback) { + globalErrorCallback(serverResp); + } + // 由调用方处理 + return Promise.reject(serverResp.msg); } } - } - throw error; -}); + notifyResponseObserver({ + config: axiosResp?.config, + status: axiosResp?.status, + response: axiosResp + }); + return axiosResp.data; + }, (error: any) => { + notifyResponseObserver({ + config: error?.config, + status: error?.response?.status, + response: error?.response, + error + }); + // 请求错误 + if (error) { + if (error.response && error.response.status) { + throw error; + } + if (error.request) { + if (error.message && error.message.startsWith("timeout")) { + throw new Error("time out"); + } else { + throw new Error(error.message || "request error"); + } + } + } + throw error; + }); +}; + +const axiosInstance = axios.create(); +applyDefaultInterceptors(axiosInstance); + +export const createServiceAxios = (baseURL?: string) => { + const instance = axios.create({ baseURL }); + applyDefaultInterceptors(instance); + return instance; +}; export default { - axios, - userTokenInterceptors, - setGlobalErrorCallback + axios: axiosInstance, + setGlobalErrorCallback, + setGlobalRequestInterceptor, + setGlobalResponseObserver, + createServiceAxios };