Skip to content

数据请求工具(Request/axios)

这个请求工具基于 Axios 封装,提供了更加简洁、功能完善的 HTTP 请求能力,包括请求/响应拦截、取消请求、统一错误处理等功能。

基本用法

创建请求实例

javascript
import { createHttpInstance } from '@pt/utils/modules/request';
import type { RequestHttp } from '@pt/utils/modules/request';

// 基础配置
const http: RequestHttp = createHttpInstance({
  axiosConfig: { baseURL: '/api' },
  onUnauthorized: () => (window.location.href = '/login')
});

// 完整配置(包含自定义token键名和请求头)
const http: RequestHttp = createHttpInstance({
  axiosConfig: {
    baseURL: '/api',
    timeout: 5000
  },
  onUnauthorized: () => (window.location.href = '/login'),
  tokenKey: 'Authorization', // 自定义token键名,默认为 'satoken'
  customHeaders: {
    'X-Custom-Header': 'value',
    'App-Version': '1.0.0'
  }
});

注意:旧版本的参数传递方式已废弃,建议使用对象参数方式进行配置。

发起请求

javascript
// GET 请求
http.get<UserInfo>('/user/info', { id: 1 }).then(res => {
  console.log(res.data);
});

// POST 请求
http.post<ResponseType>('/user/create', { 
  name: '张三', 
  age: 25 
}).then(res => {
  console.log(res);
});

// PUT 请求
http.put<ResponseType>('/user/update', { id: 1, name: '李四' });

// DELETE 请求 - 参数作为 query string
http.delete<ResponseType>('/user/delete', { id: 1 });

// DELETE 请求 - 参数作为 request body(通过 data 传递)
http.delete<any>('/api/kbFile', null, { data: { id: 1, name: 'test' } });

// DELETE 请求 - 带额外配置(如自定义headers)
http.delete<ResponseType>('/user/delete', { id: 1 }, {
  headers: { 'X-Custom': 'value' }
});

// PATCH 请求
http.patch<ResponseType>('/user/patch', { id: 1, status: 'active' });

高级配置

自定义 Token 获取方式

如果您需要从不同的存储位置获取 token,或需要自定义获取 token 的逻辑,可以使用 setTokenProvider 方法:

javascript
http.setTokenProvider(() => {
  // 自定义获取token的逻辑
  return (
    localStorage.getItem('custom_token_key') || 
    sessionStorage.getItem('token')
  );
});

添加自定义请求头

您可以使用 useCustomHeaders 方法添加多个自定义请求头:

javascript
http.useCustomHeaders(() => ({
  version: storage.get('version') || '',
  officeId: storage.get('office_id') || '',
  'Content-Type': 'application/json',
  'App-Client': 'web',
}));

链式调用

支持链式调用进行多项配置:

javascript
http
  .setTokenProvider(() => localStorage.getItem('admin_token'))
  .useCustomHeaders(() => ({
    platform: 'admin',
    version: '1.0.0'
  }));

核心功能

请求拦截

  • 自动添加 token 到请求头
  • 支持请求防重复提交
  • 可自定义请求头

响应拦截

  • 自动处理 token 过期情况
  • 统一错误处理
  • 支持请求取消

Token 处理

  • 默认使用 'satoken' 作为 token 键名
  • 支持自定义 token 键名
  • 灵活的 token 获取方式

类型支持

所有请求方法都支持泛型,便于类型推导:

typescript
interface UserInfo {
  id: number;
  name: string;
  age: number;
}

// 类型安全的请求
const userInfo = await http.get<UserInfo>('/user/info', { id: 1 });
console.log(userInfo.data.name); // TypeScript 会提供类型提示

异常处理

统一响应结构

typescript
interface ResultData<T> {
  code: number;
  message: string;
  data: T;
}

401 未授权处理

当服务器返回 401 或其他未授权状态码时,会自动触发创建实例时提供的回调函数:

javascript
createHttpInstance(
  { baseURL: '/api' },
  () => {
    // 这里处理未授权情况
    window.location.href = '/login';
    // 或者清除本地存储
    localStorage.removeItem('token');
  }
);

请求错误处理

javascript
http.get('/api/data')
  .then(res => {
    // 成功处理
  })
  .catch(error => {
    // 统一错误处理
    if (error.response) {
      // 服务器返回错误状态码
      console.error(`状态码: ${error.response.status}`);
      console.error(`错误信息: ${error.response.data.message}`);
    } else if (error.request) {
      // 请求发送但没有收到响应
      console.error('网络异常,请检查您的网络连接');
    } else {
      // 请求配置出错
      console.error(`请求异常: ${error.message}`);
    }
  });

技术实现

这个请求工具的核心是 RequestHttp 类,它封装了 Axios 实例并提供了以下功能:

  1. 请求拦截器:添加 token 和自定义头信息
  2. 响应拦截器:处理通用错误和 token 过期情况
  3. 请求取消机制:防止重复请求
  4. 方便的 HTTP 方法封装:get、post、put、delete、patch

通过工厂函数 createHttpInstance 创建实例,使得配置更加灵活和简洁。

配置选项

RequestHttpOptions

typescript
interface RequestHttpOptions {
  axiosConfig: AxiosRequestConfig;      // Axios 配置对象
  onUnauthorized?: () => void;          // 401 未授权时的回调函数
  tokenKey?: string;                    // Token 的请求头键名,默认 'satoken'
  customHeaders?: Record<string, any>;  // 固定的自定义请求头
}

最佳实践

1. 创建统一的请求实例

建议在项目的 /src/api 目录下新建一个 index.ts 文件,创建统一的请求实例:

typescript
// src/api/index.ts
import { getLoginUrl } from '@/config/config'
import { createHttpInstance } from '@pt/utils/modules/request'
import type { RequestHttp } from '@pt/utils/modules/request'

const request: RequestHttp = createHttpInstance({
  axiosConfig: {
    baseURL: import.meta.env.VITE_API_URL || ''
  },
  onUnauthorized: () => {
    window.location.href = getLoginUrl() // 401 处理逻辑
  }
})

export default request

2. 按模块组织 API 接口

src/api/modules/ 目录下按业务模块创建 API 文件:

typescript
// src/api/modules/knowledge.ts
import http from '@/api'


/* 
// src/api/config/servicePort
export const KNOW_SOURCE_V1 = '/api-know-source/v1' // 知识库v1版本
export const KNOW_SOURCE_V3 = '/api-know-source/v3' // 知识库v3版本
*/
import { KNOW_SOURCE_V1 } from '../config/servicePort'

// ==================== 知识库管理 (KbBase) ====================

// * 获取知识库分页列表
export const getKbBasePageApi = (params: any) => {
  return http.post<any>(`${KNOW_SOURCE_V1}/api/kbBase/page`, params)
}

// * 获取知识库详情
export const getKbBaseDetailApi = (id: string) => {
  return http.get<any>(`${KNOW_SOURCE_V1}/api/kbBase/${id}`)
}

// * 创建知识库
export const createKbBaseApi = (params: any) => {
  return http.post<any>(`${KNOW_SOURCE_V1}/api/kbBase`, params)
}

// * 更新知识库
export const updateKbBaseApi = (params: any) => {
  return http.patch<any>(`${KNOW_SOURCE_V1}/api/kbBase`, params)
}

// * 删除知识库
export const deleteKbBaseApi = (params: any) => {
  return http.delete<any>(`${KNOW_SOURCE_V1}/api/kbBase`, null, { data: params })
}

3. 其他最佳实践建议

  • 使用泛型获得更好的类型支持
  • 根据项目需求自定义 token 处理逻辑
  • 利用链式调用简化配置
  • 在创建实例时配置固定的请求头,使用方法动态添加可变的请求头
typescript
// 为特定模块创建独立实例(如需要)
const adminHttp = createHttpInstance({
  axiosConfig: {
    baseURL: '/api/admin',
    timeout: 10000
  },
  onUnauthorized: () => (window.location.href = '/admin/login'),
  tokenKey: 'Authorization',
  customHeaders: {
    'X-Client-Type': 'admin',
    'X-App-Version': '2.0.0'
  }
})
  .setTokenProvider(() => localStorage.getItem('admin_token'))
  .useCustomHeaders(() => ({
    role: 'admin',
    timestamp: Date.now()
  }))

迁移指南

如果您正在使用旧版本的参数传递方式,请按以下方式迁移:

旧版本(已废弃):

javascript
const http = createHttpInstance(
  { baseURL: '/api' },
  () => (window.location.href = '/login'),
  'Authorization',
  { 'X-Custom': 'value' }
);

新版本(推荐):

javascript
const http = createHttpInstance({
  axiosConfig: { baseURL: '/api' },
  onUnauthorized: () => (window.location.href = '/login'),
  tokenKey: 'Authorization',
  customHeaders: { 'X-Custom': 'value' }
});

Released under the MIT License.