feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
- 搭建 api、auth、utils 等逻辑模块 - 通过 tsc、eslint、vitest 测试验证 BREAKING CHANGE: 新镜像分支
This commit is contained in:
279
api/client.ts
Normal file
279
api/client.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
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 };
|
||||
Reference in New Issue
Block a user