complex-request
v1.1.1
Published
a complex request
Downloads
94
Maintainers
Readme
Complex Request
这是一个功能强大且高度可扩展的 TypeScript 请求库,旨在通过分层、可组合的规则引擎,优雅地处理复杂的 Web 请求场景。
核心特性
- 分层架构:
BaseRequest: 抽象请求基类,负责驱动整个请求生命周期,包括 Token 处理、请求重试、错误捕获等。Rule: 可定制的规则引擎,将所有与具体业务相关的逻辑(如响应解析、登录/刷新流程)集中管理。Token: 封装单个 Token 的所有行为,包括值的获取、存储、附加到请求和生命周期管理。
- 强大的 Token 管理:
- 支持多个具名
Token和一个refreshToken。 - 支持从内存、
localStorage和sessionStorage中自动获取和缓存 Token。 - 可配置 Token 的有效期、存储位置(
header,body,params)和附加键名。 - 自动化的登录和刷新流程,当 Token 失效时,可自动触发
login或refresh操作,并无缝地重试原始请求。
- 支持多个具名
- 高度可定制:
- 响应解析: 可通过
parse函数,将任何格式的服务器响应,适配为统一的{ status, data, ... }格式。 - 请求格式化: 可通过
format函数,在请求发送前,对请求参数进行最后一次修改。 - 底层实现无关:
BaseRequest是一个抽象类,您可以继承它,并使用任何底层的请求库(如axios,fetch)来实现$request方法。
- 响应解析: 可通过
- 数据格式转换:
- 支持在
json和form-data之间自动转换请求数据。
- 支持在
安装
npm install complex-request快速开始
下面是一个使用 fetch 作为底层实现的简单示例:
import { BaseRequest, Rule, Token } from 'complex-request';
// 1. 创建一个继承自 BaseRequest 的具体请求类
// 我们在这里为泛型 R (原始响应) 和 L (本地配置) 提供了具体的类型
class MyRequest extends BaseRequest<any, { signal?: AbortSignal }> {
$request(requestConfig) {
// 使用 fetch 实现底层的请求逻辑
const { url, method, headers, data, params, local } = requestConfig;
const finalUrl = new URL(url);
Object.keys(params).forEach(key => finalUrl.searchParams.append(key, params[key]));
return fetch(finalUrl.toString(), {
method,
headers,
body: data,
signal: local?.signal // 传递 AbortSignal 以便取消请求
}).then(res => res.json());
}
$parseError(error) {
// 解析 fetch 抛出的错误
return { type: 'internal', msg: error.message, data: error };
}
}
// 2. 定义一套规则
const myRule = new Rule({
prop: 'api',
token: {
data: {
// 定义一个名为 'accessToken' 的 Token
accessToken: {
location: 'header', // 存储在 Header 中
require: true // 这是一个必需的 Token
}
}
},
parse: (response) => {
// 解析服务器响应
if (response.code === 200) {
return { status: 'success', data: response.data };
} else if (response.code === 401) {
return { status: 'login', data: null, msg: '请先登录' };
} else {
return { status: 'fail', data: null, msg: response.message };
}
},
login: () => {
// 定义登录逻辑
return new Promise(resolve => {
// ... 执行登录操作,例如弹出一个登录框
// ... 登录成功后,使用 setToken 设置新的 Token
myRequest.setToken('accessToken', 'new-token-from-server');
resolve();
});
}
});
// 3. 实例化请求对象
const myRequest = new MyRequest({
baseUrl: 'https://api.example.com',
rule: myRule
});
// 4. 发送请求
// 4. 发送请求,并传递一个本地配置
const controller = new AbortController();
myRequest.get({
url: '/user/profile',
local: { signal: controller.signal }
})
.then(response => {
console.log('用户信息:', response.data);
})
.catch(error => {
console.error('请求失败:', error);
});
// 可以在需要时取消请求
// controller.abort();高级用法:泛型类型
complex-request 大量使用泛型来提供强大的类型安全。理解 R 和 L 这两个核心泛型,能帮助您更好地利用这个库。
R - 原始响应 (Raw Response)
R 代表的是底层请求工具(如 fetch, axios)直接返回的、未经 rule.parse 解析的原始响应数据的类型。
在 Rule 的 parse 函数中,response 参数的类型就是 R。
// 假设服务器返回的数据结构是 { code: number, data: T, message: string }
type ServerResponse<T> = {
code: number;
data: T;
message: string;
}
// 在定义 Rule 时,我们可以将 R 指定为 ServerResponse<any>
const myRule = new Rule<ServerResponse<any>>({
// ...
parse: (response) => { // 在这里,`response` 的类型就是 ServerResponse<any>
if (response.code === 200) {
return { status: 'success', data: response.data };
}
// ...
}
});L - 本地配置 (Local Config)
L 代表的是一个可选的、用于传递给底层请求工具的、特定于实现的配置对象的类型。
这非常有用,因为不同的底层请求库(fetch, axios)有它们自己独特的配置选项(例如,axios 的 cancelToken,fetch 的 signal)。L 允许您以类型安全的方式,将这些特定于实现的配置,一路传递到您自己实现的 $request 方法中。
在上面的“快速开始”示例中,我们通过 L 泛型,为 fetch 实现了一个请求取消的功能。
parse 函数:请求的“交通警察”
parse 函数是 complex-request 库的核心。它就像一个交通警察,负责检查每一个从服务器返回的原始响应 (R),并根据您定义的业务逻辑,告诉 BaseRequest 下一步应该做什么。
parse 函数必须返回一个 responseType 对象,其 status 字段决定了整个请求的走向:
interface responseType<D = any> {
status: 'success' | 'fail' | 'login' | 'refresh'
data: D
code?: number | string
msg?: string
}下面是 BaseRequest 对每种 status 的处理方式:
'success': 请求成功- 含义: 服务器成功处理了请求,且响应数据是有效的。
BaseRequest的行为:request方法返回的 Promise 将被 resolve,并将data字段作为结果传递下去。
'fail': 请求失败- 含义: 服务器返回了一个业务逻辑上的错误(例如,表单验证失败、权限不足等)。
BaseRequest的行为:request方法返回的 Promise 将被 reject,并将整个responseType对象作为错误信息传递下去。
'login': 需要登录- 含义: 用户的会话已完全失效,必须重新登录。
BaseRequest的行为:- 自动触发您在
Rule中定义的login函数。 - 在
login函数成功执行后(即其返回的 Promise 被 resolve),BaseRequest会自动重新发送之前失败的那个请求。 - 整个过程对最终的调用者是完全透明的。
- 自动触发您在
'refresh': 需要刷新 Token- 含义: 用户的访问令牌(Access Token)已过期,但刷新令牌(Refresh Token)仍然有效。
BaseRequest的行为:- 自动触发您在
Rule中定义的refresh函数。 - 在
refresh函数成功执行后,BaseRequest会自动重新发送之前失败的那个请求。 - 如果
refresh本身也失败了,或者刷新后重试的请求依然返回'refresh',BaseRequest会自动将流程降级为'login'。
- 自动触发您在
通过精心设计您的 parse 函数,您可以以一种非常优雅和集中的方式,实现极其复杂的认证和重试逻辑。
依赖
- complex-utils: 提供核心的工具函数和基类。
- complex-plugin: 提供
notice通知插件。
