request-core-adapter
v1.0.1
Published
基于适配器模式的统一请求工具库
Maintainers
Readme
request-core
一个基于适配器模式的 HTTP 请求库,支持 umi-request 和 axios,提供统一的 API 接口和丰富的功能特性。
✨ 特性
- 🔌 适配器模式:支持 umi-request 和 axios,可轻松扩展其他 HTTP 客户端
- 🔐 自动认证:自动添加 Authorization 和 tenant-id 请求头
- 🚫 重复请求取消:支持取消重复的请求,避免资源浪费
- 📊 业务状态码处理:灵活处理业务状态码,支持自定义允许的状态码
- 🎯 统一错误处理:统一的错误处理机制,支持自定义错误提示
- 📝 请求日志:内置请求日志功能,方便调试
- 🛡️ 类型安全:完整的 TypeScript 类型定义
- ⚡ 401 自动处理:自动处理未授权状态,触发回调
📦 安装
pnpm add request-core
# 或
npm install request-core
# 或
yarn add request-core🚀 快速开始
基础用法
import { createRequest } from 'request-core';
import { message } from 'antd'; // 或其他 UI 库
const request = createRequest({
baseUrl: 'https://api.example.com',
adapterType: 'umi', // 或 'axios'
getToken: () => localStorage.getItem('token'),
getTenantId: () => localStorage.getItem('tenantId'),
enableLog: true,
onUnauthorized: () => {
// 处理未授权
window.location.href = '/login';
},
onErrorTip: (msg, error) => {
// 统一错误提示
message.error(msg);
},
onError: (error) => {
// 错误处理回调
console.error('Request error:', error);
},
});
// 使用
const data = await request.get('/api/users');使用 Axios 适配器
import axios from 'axios';
import { createRequest } from 'request-core';
const axiosInstance = axios.create({
timeout: 10000,
});
const request = createRequest({
adapterType: 'axios',
axiosInstance,
baseUrl: 'https://api.example.com',
getToken: () => localStorage.getItem('token'),
});📖 API 文档
createRequest(options)
创建请求实例。
参数
interface CreateOptions extends RequestGlobalConfig {
adapterType?: 'umi' | 'axios'; // 适配器类型,默认为 'umi'
axiosInstance?: AxiosInstance; // 使用 axios 适配器时必需
}返回值
返回一个包含以下方法的请求对象:
{
get: <T>(url: string, params?: any, config?: RequestConfig) => Promise<ResponseData<T>>;
post: <T>(url: string, data?: any, config?: RequestConfig) => Promise<ResponseData<T>>;
put: <T>(url: string, data?: any, config?: RequestConfig) => Promise<ResponseData<T>>;
delete: <T>(url: string, data?: any, config?: RequestConfig) => Promise<ResponseData<T>>;
}请求方法
get<T>(url, params?, config?)
发送 GET 请求。
const users = await request.get<User[]>('/api/users', { page: 1, size: 10 });post<T>(url, data?, config?)
发送 POST 请求。
const user = await request.post<User>('/api/users', {
name: 'John',
email: '[email protected]',
});put<T>(url, data?, config?)
发送 PUT 请求。
const user = await request.put<User>('/api/users/1', {
name: 'John Updated',
});delete<T>(url, data?, config?)
发送 DELETE 请求。
await request.delete('/api/users/1');⚙️ 配置选项
RequestGlobalConfig
全局配置选项:
| 选项 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| baseUrl | string | 基础 URL | - |
| getToken | () => string \| null | 获取 token 的函数 | - |
| getTenantId | () => string \| null | 获取租户 ID 的函数 | - |
| onUnauthorized | () => void | 401 未授权回调 | - |
| onErrorTip | (message: string, error: any) => void | 错误提示回调 | - |
| onError | (error: any) => void | 错误处理回调 | - |
| enableLog | boolean | 是否启用日志 | false |
RequestConfig
请求配置选项(可在每次请求时覆盖):
| 选项 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| showError | boolean | 是否显示错误提示 | true |
| throwError | boolean | 是否抛出错误 | true |
| errorMessage | string | 自定义错误消息 | - |
| businessStatusCodes | number[] | 允许的业务状态码 | [409] |
| cancelDuplicate | boolean | 是否取消重复请求 | false |
| headers | Record<string, string> | 自定义请求头 | - |
| signal | AbortSignal | 取消信号 | - |
📝 使用示例
基础请求
// GET 请求
const users = await request.get('/api/users');
// POST 请求
const newUser = await request.post('/api/users', {
name: 'John',
email: '[email protected]',
});
// PUT 请求
const updatedUser = await request.put('/api/users/1', {
name: 'John Updated',
});
// DELETE 请求
await request.delete('/api/users/1');带参数的请求
// GET 请求带查询参数
const users = await request.get('/api/users', {
page: 1,
size: 10,
keyword: 'john',
});
// POST 请求带数据
const result = await request.post('/api/users', {
name: 'John',
email: '[email protected]',
});自定义配置
// 不显示错误提示
const data = await request.get('/api/users', {}, {
showError: false,
});
// 不抛出错误,返回错误响应
const result = await request.post('/api/users', userData, {
throwError: false,
});
// 自定义错误消息
const result = await request.post('/api/users', userData, {
errorMessage: '创建用户失败,请重试',
});
// 允许特定的业务状态码
const result = await request.post('/api/users', userData, {
businessStatusCodes: [409, 422],
});
// 取消重复请求
const result = await request.get('/api/users', {}, {
cancelDuplicate: true,
});错误处理
try {
const user = await request.get('/api/users/1');
} catch (error) {
// 处理错误
console.error('Request failed:', error);
}
// 或者不抛出错误
const result = await request.get('/api/users/1', {}, {
throwError: false,
});
if (result.code !== 200) {
console.error('Request failed:', result.message);
}取消请求
const controller = new AbortController();
request.get('/api/users', {}, {
signal: controller.signal,
});
// 取消请求
controller.abort();🔌 适配器
Umi-Request 适配器
默认适配器,基于 umi-request。
const request = createRequest({
adapterType: 'umi',
baseUrl: 'https://api.example.com',
});Axios 适配器
使用 axios 作为 HTTP 客户端。
import axios from 'axios';
const axiosInstance = axios.create({
timeout: 10000,
});
const request = createRequest({
adapterType: 'axios',
axiosInstance,
baseUrl: 'https://api.example.com',
});自定义适配器
你可以实现 HttpAdapter 接口来创建自定义适配器:
import { HttpAdapter } from 'request-core';
import { RequestConfig, AdapterResponse } from 'request-core';
const myAdapter: HttpAdapter = {
request: async (url: string, options: RequestConfig): Promise<AdapterResponse> => {
// 实现你的请求逻辑
const response = await fetch(url, {
method: options.method,
headers: options.headers,
body: options.data ? JSON.stringify(options.data) : undefined,
});
return {
data: await response.json(),
status: response.status,
headers: Object.fromEntries(response.headers.entries()),
};
},
};📋 类型定义
ResponseData
interface ResponseData<T = any> {
code: number;
message: string;
data: T;
error?: any;
}RequestConfig
interface RequestConfig extends Omit<RequestOptionsInit, 'data' | 'params'> {
data?: any;
params?: any;
errorMessage?: string;
showError?: boolean;
throwError?: boolean;
businessStatusCodes?: number[];
enableLog?: boolean;
cancelDuplicate?: boolean;
}RequestGlobalConfig
interface RequestGlobalConfig {
baseUrl?: string;
getToken?: () => string | null;
getTenantId?: () => string | null;
onUnauthorized?: () => void;
onErrorTip?: (message: string, error: any) => void;
onError?: (error: any) => void;
enableLog?: boolean;
}
interface AdapterResponse<T = any> {
data: T;
status: number;
headers?: any;
}
interface HttpAdapter {
request: (url: string, options: RequestConfig) => Promise<AdapterResponse>;
}🎯 业务状态码处理
默认情况下,只有 code === 200 或 code === 0 的响应会被视为成功。你可以通过 businessStatusCodes 配置允许其他状态码:
// 允许 409 和 422 状态码
const result = await request.post('/api/users', userData, {
businessStatusCodes: [409, 422],
});默认允许的状态码是 [409]。
🚫 重复请求取消
启用 cancelDuplicate 选项后,相同的请求(相同的 method、url、params、data)会自动取消之前的请求:
const result = await request.get('/api/users', {}, {
cancelDuplicate: true,
});📝 日志
启用日志后,会在控制台输出请求信息:
const request = createRequest({
enableLog: true,
// ...
});
// 输出示例:
// 🚀 GET https://api.example.com/api/users
// ✅ GET https://api.example.com/api/users 234ms
// ❌ POST https://api.example.com/api/users 123ms Error: ...🔐 认证
自动添加认证信息到请求头:
const request = createRequest({
getToken: () => localStorage.getItem('token'),
getTenantId: () => localStorage.getItem('tenantId'),
});
// 请求会自动添加:
// Authorization: Bearer <token>
// tenant-id: <tenantId>⚠️ 错误处理
自动错误提示
通过 onErrorTip 回调统一处理错误提示:
import { message } from 'antd';
const request = createRequest({
onErrorTip: (msg, error) => {
message.error(msg);
},
});401 未授权处理
自动检测 401 状态码并触发回调:
const request = createRequest({
onUnauthorized: () => {
// 清除 token
localStorage.removeItem('token');
// 跳转到登录页
window.location.href = '/login';
},
});取消请求处理
当请求被取消时(AbortError),会返回一个特殊的响应:
{
code: -1,
message: 'canceled',
data: null
}📄 License
ISC
🤝 贡献
欢迎提交 Issue 和 Pull Request!
