feat(reset): 以构造器模式重构

- 加了大文件传输自定义分片协议

BREAKING CHANGES: 0.1.0(latest)
This commit is contained in:
tobegold574
2025-11-30 20:27:53 +08:00
parent c5853847ae
commit 382e3aff21
82 changed files with 1421 additions and 7010 deletions

62
client/axios-client.ts Normal file
View File

@@ -0,0 +1,62 @@
// 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 || '未知错误类型',
});
}
}
}

40
client/common.ts Normal file
View File

@@ -0,0 +1,40 @@
// common.ts —— 各协议共用的统一请求配置格式
export interface BaseRequestConfig {
url: string;
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
headers?: Record<string, string>;
query?: Record<string, string | number>; // 暂时也就分页和搜索
body?: any;
timeout?: number;
withCredentials?: boolean;
// upload的时候处理表单要用避免axios处理
transformRequest?: ((data: any) => any) | ((data: any) => any)[];
}
// 设计Mock或者实际后端的时候也直接对应这个接口
export interface BaseResponseConfig<T = unknown> {
status: number; // 状态码HTTP状态码
msg?: string; // 报错信息可以没有和error不是一层语义
data: T;
}
/*
* 基础错误类client层
*/
export class BaseError extends Error {
code: string; // 错误码(字符串)
response?: BaseResponseConfig;
constructor({ message, code, response }: { message: string; code: string; response?: BaseResponseConfig }) {
super(message);
this.name = 'BaseError'; // 补充缺失的 name 属性会在toString()打印ES5规范还是遵守一下吧
this.code = code;
if (response) {
this.response = response;
}
}
}

2
client/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './axios-client';
export * from './common';