@tni/http
v2.0.0
Published
Axios 请求封装
Downloads
112
Readme
@tni/http
基于 axios 的 HTTP 请求封装,设计风格参考 vben-admin,适合统一管理项目里的 API 调用行为。
内置能力包括:
- 请求/响应拦截
- 自动拼接
apiUrl和urlPrefix - 自动注入 token
- 重复请求取消
- 统一响应转换
- 401 未登录回调
- GET/HEAD 请求失败重试
requestOptions统一控制请求行为
安装
vp add @tni/http导出内容
import {
createAxios,
defHttp,
VAxios,
HttpResponseError,
type CreateAxiosOptions,
type RequestOptions,
} from "@tni/http";快速开始
import { createAxios } from "@tni/http";
const http = createAxios({
requestOptions: {
apiUrl: "https://api.example.com",
urlPrefix: "/v1",
},
authentication: {
getToken: () => localStorage.getItem("token") ?? undefined,
},
});
// 默认返回 res.data,并自动兼容常见 { code, data/result, message } 响应结构
const data = await http.get<{ list: string[] }>({ url: "/demo" });如何使用
1. 创建一个项目级 HTTP 实例
通常建议在业务项目中单独封装一个 http.ts,统一设置接口域名、前缀和鉴权逻辑。
import { createAxios } from "@tni/http";
export const http = createAxios({
timeout: 10_000,
requestOptions: {
apiUrl: "https://api.example.com",
urlPrefix: "/api",
},
authentication: {
getToken: () => localStorage.getItem("token") ?? undefined,
onUnauthorized: () => {
localStorage.removeItem("token");
window.location.href = "/login";
},
},
});如果不需要自定义配置,也可以直接使用默认实例:
import { defHttp } from "@tni/http";2. 发起 GET 请求
type User = {
id: number;
name: string;
};
const users = await http.get<User[]>({
url: "/users",
params: {
page: 1,
pageSize: 20,
},
});3. 发起 POST / PUT / DELETE 请求
await http.post({
url: "/users",
data: {
name: "Alice",
},
});
await http.put({
url: "/users/1",
data: {
name: "Bob",
},
});
await http.delete({
url: "/users/1",
});4. 覆盖单次请求配置
第二个参数可以传入 requestOptions,覆盖当前请求的行为。
const detail = await http.get(
{
url: "/users/detail",
params: { id: 1 },
},
{
withToken: false,
joinTime: false,
errorMessageMode: "none",
},
);5. 获取原始响应对象
默认情况下,@tni/http 返回的是转换后的业务数据。如果你需要状态码、响应头等原始响应信息,可以使用 request 并开启 isReturnNativeResponse。
const response = await http.request<{ id: number; name: string }>(
{
url: "/users/1",
method: "GET",
},
{
isReturnNativeResponse: true,
},
);
console.log(response.status);
console.log(response.data);6. 处理业务错误
默认响应转换会把以下结构识别为业务响应:
{
code: 0,
data: {},
message: "success"
}或:
{
code: 200,
result: {},
msg: "success"
}当 code 不在成功码列表中时,会抛出 HttpResponseError:
import { HttpResponseError } from "@tni/http";
try {
await http.get({ url: "/users/1" });
} catch (error) {
if (error instanceof HttpResponseError) {
console.error(error.code);
console.error(error.message);
console.error(error.data);
}
}默认行为
createAxios() 默认配置如下:
| 配置项 | 默认值 | 说明 |
| --------------------------------------- | -------------------------------- | ----------------------------- |
| timeout | 10000 | 请求超时时间 |
| headers["Content-Type"] | application/json;charset=utf-8 | 默认请求头 |
| authentication.headerName | Authorization | token 请求头名称 |
| authentication.tokenPrefix | Bearer | token 前缀 |
| requestOptions.isJoinPrefix | true | 自动拼接 urlPrefix |
| requestOptions.joinParamsToUrl | false | 是否把 params 直接拼到 URL |
| requestOptions.formatDate | true | 自动把 Date 转成 ISO 字符串 |
| requestOptions.joinTime | true | GET 请求自动追加时间戳 _t |
| requestOptions.isTransformResponse | true | 自动处理业务响应结构 |
| requestOptions.isReturnNativeResponse | false | 默认不返回原始响应对象 |
| requestOptions.withToken | true | 默认自动带 token |
| requestOptions.successCodes | [0, 200] | 业务成功码 |
| requestOptions.errorMessageMode | "console" | 错误输出方式 |
常用配置说明
requestOptions
| 配置项 | 类型 | 说明 |
| ------------------------ | --------------------------------------------- | ----------------------------------- |
| apiUrl | string | 接口基础地址,会写入 baseURL |
| urlPrefix | string | 接口公共前缀,如 /api、/v1 |
| isJoinPrefix | boolean | 是否自动拼接 urlPrefix |
| joinParamsToUrl | boolean | 是否把 params 序列化到 URL 上 |
| formatDate | boolean | 是否递归格式化 Date 为 ISO 字符串 |
| joinTime | boolean | GET 请求是否自动追加时间戳参数 |
| isTransformResponse | boolean | 是否启用默认响应转换 |
| isReturnNativeResponse | boolean | 是否直接返回 Axios 原始响应 |
| successMessageMode | "none" \| "console" \| "message" \| "modal" | 成功消息输出模式 |
| errorMessageMode | "none" \| "console" \| "message" \| "modal" | 错误消息输出模式 |
| ignoreCancelToken | boolean | 是否跳过重复请求取消逻辑 |
| withToken | boolean | 是否自动注入 token |
| successCodes | number[] | 业务成功码列表 |
| retryRequest | RetryRequestOptions | 失败重试配置 |
authentication
| 配置项 | 类型 | 说明 |
| ---------------- | --------------------------- | ------------------------ |
| headerName | string | token 请求头名称 |
| tokenPrefix | string | token 前缀,如 Bearer |
| getToken | () => string \| undefined | 获取 token 的方法 |
| onUnauthorized | (err: unknown) => void | 接口返回 401 时触发 |
进阶用法
自定义拦截与响应转换
可以通过 transform 扩展请求前处理、响应处理和错误处理逻辑。
const http = createAxios({
transform: {
beforeRequestHook: (config) => {
config.headers = config.headers ?? {};
config.headers["X-Trace-Id"] = crypto.randomUUID();
return config;
},
responseInterceptors: (res) => {
console.log("response status:", res.status);
return res;
},
},
});开启 GET 请求失败重试
重试仅对 GET 和 HEAD 请求生效,且默认更适合处理网络异常或 5xx 错误。
const data = await http.get(
{
url: "/reports",
},
{
retryRequest: {
isOpenRetry: true,
count: 2,
waitTime: 1000,
},
},
);取消当前实例下的全部待处理请求
http.cancelAllRequests();适用的默认响应结构
默认转换逻辑会优先读取这些字段:
codemessage或msgdata或result
也就是说,以下响应都能直接拿到业务数据:
const list = await http.get<string[]>({ url: "/list" });后端返回:
{ "code": 0, "data": ["a", "b"], "message": "ok" }或:
{ "code": 200, "result": ["a", "b"], "msg": "ok" }