Files
knowai/api/client.ts
tobegold574 6a81b7bb13
Some checks reported errors
continuous-integration/drone/push Build was killed
feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
- 搭建 api、auth、utils 等逻辑模块
- 通过 tsc、eslint、vitest 测试验证

BREAKING CHANGE: 新镜像分支
2025-11-10 20:20:25 +08:00

280 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import axios from 'axios';
import type { ApiClient } from './types';
import type { AxiosError, AxiosResponse, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';
import { ApiError } from './errors'; // 直接导入ApiError
// 创建API客户端实例的工厂函数
const createApiClientInstance = (config?: Partial<AxiosRequestConfig>): ApiClient => {
// 创建axios实例
const instance = axios.create({
baseURL: '/api', // Core层使用默认值具体配置由Runtime层注入
timeout: 10000,
headers: {
'Content-Type': 'application/json'
},
withCredentials: true, // 允许跨域携带cookie
...config // 应用传入的配置
});
// 请求拦截器数组
const requestInterceptors: Array<number> = [];
// 响应拦截器数组
const responseInterceptors: Array<number> = [];
// 添加请求拦截器
const addRequestInterceptor = (
onFulfilled?: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = instance.interceptors.request.use(onFulfilled, onRejected);
requestInterceptors.push(handler);
return handler;
};
// 添加响应拦截器
const addResponseInterceptor = (
onFulfilled?: (_response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = instance.interceptors.response.use(onFulfilled, onRejected);
responseInterceptors.push(handler);
return handler;
};
// 移除请求拦截器
const removeRequestInterceptor = (handler: number): void => {
const index = requestInterceptors.indexOf(handler);
if (index !== -1) {
instance.interceptors.request.eject(handler);
requestInterceptors.splice(index, 1);
}
};
// 移除响应拦截器
const removeResponseInterceptor = (handler: number): void => {
const index = responseInterceptors.indexOf(handler);
if (index !== -1) {
instance.interceptors.response.eject(handler);
responseInterceptors.splice(index, 1);
}
};
// 设置默认配置
const setDefaults = (_config: Partial<AxiosRequestConfig>): void => {
Object.assign(instance.defaults, _config);
};
// 更新基础URL - 专门用于Runtime层配置
const setBaseURL = (baseURL: string): void => {
instance.defaults.baseURL = baseURL;
};
// 创建新实例 - 用于跨域请求等特殊场景
const createInstance = (config?: Partial<AxiosRequestConfig>): ApiClient => {
// 创建新的axios实例
const newInstance = axios.create({
...instance.defaults,
...config
});
// 为新实例创建拦截器数组
const newRequestInterceptors: Array<number> = [];
const newResponseInterceptors: Array<number> = [];
// 复制拦截器
requestInterceptors.forEach(handler => {
// 由于AxiosInterceptorManager类型定义中没有handlers属性
// 我们使用类型断言来访问内部属性
type RequestHandlerType = {
id: number;
fulfilled: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
rejected: (_error: unknown) => unknown;
};
type RequestManagerType = {
handlers?: Array<RequestHandlerType>;
};
const requestManager = instance.interceptors.request as unknown as RequestManagerType;
const originalInterceptor = requestManager.handlers?.find((h: RequestHandlerType) => h.id === handler);
if (originalInterceptor) {
const newHandler = newInstance.interceptors.request.use(
originalInterceptor.fulfilled,
originalInterceptor.rejected
);
newRequestInterceptors.push(newHandler);
}
});
responseInterceptors.forEach(handler => {
// 由于AxiosInterceptorManager类型定义中没有handlers属性
// 我们使用类型断言来访问内部属性
type ResponseHandlerType = {
id: number;
fulfilled: (_response: AxiosResponse) => AxiosResponse;
rejected: (_error: AxiosError) => unknown;
};
type ResponseManagerType = {
handlers?: Array<ResponseHandlerType>;
};
const responseManager = instance.interceptors.response as unknown as ResponseManagerType;
const originalInterceptor = responseManager.handlers?.find((h: ResponseHandlerType) => h.id === handler);
if (originalInterceptor) {
const newHandler = newInstance.interceptors.response.use(
originalInterceptor.fulfilled,
originalInterceptor.rejected
);
newResponseInterceptors.push(newHandler);
}
});
// 返回一个符合ApiClient接口的对象
return {
request: async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
try {
const response = await newInstance.request<T>(config);
return response.data;
} catch (error) {
// 直接使用ApiError.fromAxiosError静态方法处理错误
return Promise.reject(ApiError.fromAxiosError(error as AxiosError));
}
},
get: <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'GET', url }).then((res: AxiosResponse<T>) => res.data);
},
post: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'POST', url, data }).then((res: AxiosResponse<T>) => res.data);
},
put: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'PUT', url, data }).then((res: AxiosResponse<T>) => res.data);
},
delete: <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'DELETE', url }).then((res: AxiosResponse<T>) => res.data);
},
patch: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return newInstance.request<T>({ ...config, method: 'PATCH', url, data }).then((res: AxiosResponse<T>) => res.data);
},
setDefaults: (_config: Partial<AxiosRequestConfig>): void => {
Object.assign(newInstance.defaults, _config);
},
setBaseURL: (baseURL: string): void => {
newInstance.defaults.baseURL = baseURL;
},
createInstance: (newConfig?: Partial<AxiosRequestConfig>): ApiClient => {
// 手动处理headers字段的类型转换
const { headers, ...otherDefaults } = newInstance.defaults;
const configWithTypedHeaders: Partial<AxiosRequestConfig> = {
...otherDefaults,
...newConfig
};
// 只有当headers存在时才添加
if (headers) {
// 手动转换headers字段确保类型安全
const convertedHeaders: Record<string, string | number | boolean> = {};
Object.entries(headers).forEach(([key, value]) => {
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
convertedHeaders[key] = value;
}
});
configWithTypedHeaders.headers = convertedHeaders;
}
return createInstance(configWithTypedHeaders);
},
addRequestInterceptor: (
onFulfilled?: (_config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = newInstance.interceptors.request.use(onFulfilled, onRejected);
newRequestInterceptors.push(handler);
return handler;
},
addResponseInterceptor: (
onFulfilled?: (_response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
onRejected?: (_error: unknown) => unknown
): number => {
const handler = newInstance.interceptors.response.use(onFulfilled, onRejected);
newResponseInterceptors.push(handler);
return handler;
},
removeRequestInterceptor: (handler: number): void => {
const index = newRequestInterceptors.indexOf(handler);
if (index !== -1) {
newInstance.interceptors.request.eject(handler);
newRequestInterceptors.splice(index, 1);
}
},
removeResponseInterceptor: (handler: number): void => {
const index = newResponseInterceptors.indexOf(handler);
if (index !== -1) {
newInstance.interceptors.response.eject(handler);
newResponseInterceptors.splice(index, 1);
}
}
};
};
// 基础请求方法
const request = async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
try {
const response = await instance.request<T>(config);
return response.data;
} catch (error) {
// 直接使用ApiError.fromAxiosError静态方法处理错误
return Promise.reject(ApiError.fromAxiosError(error as AxiosError));
}
};
// HTTP方法简写
const get = <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'GET', url });
};
const post = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'POST', url, data });
};
const put = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'PUT', url, data });
};
const del = <T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'DELETE', url });
};
const patch = <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> => {
return request<T>({ ...config, method: 'PATCH', url, data });
};
return {
request,
get,
post,
put,
delete: del,
patch,
setDefaults,
setBaseURL,
createInstance,
addRequestInterceptor,
addResponseInterceptor,
removeRequestInterceptor,
removeResponseInterceptor
};
};
// 默认实例(单例)
const apiClient = createApiClientInstance();
// 工厂函数
const createApiClient = (config?: Partial<AxiosRequestConfig>) => {
return createApiClientInstance(config);
};
// 导出API客户端和工厂函数
export { apiClient, createApiClient };