63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
// axios-client.ts
|
||
import axios, {
|
||
type AxiosInstance,
|
||
type AxiosRequestConfig,
|
||
AxiosError,
|
||
} from 'axios';
|
||
|
||
import type { BaseRequestConfig, BaseResponseConfig } from './common';
|
||
import { BaseError } from './common';
|
||
|
||
export interface HttpClient {
|
||
request<T = unknown>(config: BaseRequestConfig): Promise<T>;
|
||
|
||
// 拦截器先别管
|
||
}
|
||
|
||
export class AxiosHttpClient implements HttpClient {
|
||
private instance: AxiosInstance;
|
||
|
||
// 不需要工厂,defaults和request的配置是相通的,单例不会输出config参数
|
||
constructor() {
|
||
this.instance = axios.create();
|
||
}
|
||
|
||
async request<T = unknown>(config: BaseRequestConfig): Promise<T> {
|
||
// ---- 映射层:BaseConfig → AxiosConfig ----
|
||
const axiosConfig: AxiosRequestConfig = {
|
||
url: config.url,
|
||
method: config.method.toLowerCase(),
|
||
headers: config.headers || {},
|
||
params: config.query || {},
|
||
// 这里做了映射,上层可以用body
|
||
data: config.body || {},
|
||
|
||
// 其实可以直接放进defaults,但是为了和request的配置保持一致,就不这么做了
|
||
timeout: config.timeout || 10000,
|
||
withCredentials: config.withCredentials || true,
|
||
};
|
||
|
||
// 类型化请求响应(直接赋值,避免额外的类型检查)
|
||
try {
|
||
const { data: res } = await this.instance.request<BaseResponseConfig<T>>(axiosConfig);
|
||
return res.data;
|
||
} catch (error: unknown) {
|
||
// 类型断言,确保 error 是 AxiosError 类型
|
||
if (axios.isAxiosError(error)) {
|
||
throw new BaseError({
|
||
message: (error as AxiosError).message || '未知错误',
|
||
code: (error as AxiosError).code || '未知错误类型',
|
||
response: (error as AxiosError).response?.data as BaseResponseConfig<T>,
|
||
});
|
||
}
|
||
|
||
throw new BaseError({
|
||
message: (error as Error).message || '未知错误',
|
||
code: (error as Error).name || '未知错误类型',
|
||
});
|
||
}
|
||
|
||
}
|
||
|
||
}
|