基于TypeScript封装Axios成通用工具类
Axios 是一款基于 Promise 的 HTTP 客户端,可用于浏览器和 Node.js 环境。它提供了丰富的功能,如请求/响应拦截器、取消请求、自动转换 JSON 等,使其成为前端和后端 HTTP 请求的流行选择。然而,在大型项目中直接使用裸露的 Axios 实例往往不够高效和灵活。通过 TypeScript 封装 Axios 成通用工具类,我们可以实现:统一的请求配置、自动的错误处理、请求/响应的标准化、方便的业务逻辑扩展,以及通过 TypeScript 带来的类型安全和代码智能提示,从而提升开发效率和代码质量。
核心思想:
将 Axios 的强大功能(如拦截器、配置)整合到一个类型安全的 TypeScript 类中,提供一个统一、可配置、易用的 HTTP 请求接口,并处理常见的业务场景,从而提升项目的可维护性和开发体验。
一、为什么需要封装 Axios?
直接使用 Axios 发送请求虽然简单,但在实际项目中会遇到以下问题:
- 重复配置:每个请求都可能需要设置
baseURL、timeout、headers等,导致大量重复代码。 - 错误处理不统一:网络错误、业务逻辑错误等需要各自处理,缺乏统一的捕获和反馈机制。
- 请求参数/响应数据格式不统一:服务器返回的数据结构可能不尽相同,需要手动解析和转换。
- 接口易变动:后端接口地址或参数变更时,可能需要修改多处代码。
- 缺乏类型检查:裸露的 JavaScript 代码在参数传递和响应数据结构上缺乏类型约束,易引发运行时错误。
- 业务逻辑耦合:一些与请求相关的业务逻辑(如身份认证、Loading 状态管理)散落在各个组件中。
封装 Axios 可以很好地解决这些问题:
- 统一管理:所有请求共用一套配置和处理逻辑。
- 自动化处理:利用 Axios 拦截器实现请求头设置、Token 刷新、Loading 显示、错误弹窗等自动化功能。
- 类型安全:借助 TypeScript 定义请求参数、响应数据、错误类型,提高代码健壮性。
- 增强可维护性:所有 HTTP 请求相关逻辑集中管理,便于修改和扩展。
- 提升开发效率:提供简洁的 API 接口,减少重复编码。
二、封装思路与核心功能点
一个通用的 Axios 封装工具类通常包含以下核心功能点:
- 创建 Axios 实例:允许创建多个具有不同配置的 Axios 实例(例如,应对多个后端服务或不同认证机制)。
- 默认配置:设置
baseURL、timeout、默认headers等。 - 请求拦截器 (Request Interceptors):
- 统一添加 Token 到
Authorization请求头。 - 统一处理请求参数,如加密、序列化等。
- 显示 Loading 状态。
- 统一添加 Token 到
- 响应拦截器 (Response Interceptors):
- 统一处理 HTTP 状态码错误(如 401、403、500)。
- 统一处理后端返回的业务逻辑错误码。
- 标准化响应数据结构。
- 隐藏 Loading 状态。
- Token 过期刷新机制。
- 错误处理:统一的错误提示(Toast/Modal),可选的错误重试机制。
- 请求方法封装:提供
get,post,put,delete等方法的类型安全封装。 - 泛型支持:通过泛型定义请求参数和响应数据的类型。
- 取消请求:提供便捷的取消请求能力。
三、TypeScript 封装 Axios 示例
我们将创建一个 HttpRequest.ts 文件,其中包含核心的封装逻辑。
3.1 定义类型 (types.ts)
首先,定义一些基础类型,以增强代码的可读性和类型安全。
1 | // types.ts |
3.3 如何使用 (main.ts / services/user.ts)
1 | // main.ts 或 services/user.ts |
四、核心封装点解析
HttpRequest类:instance: 私有AxiosInstance实例,确保每个HttpRequest实例都有独立的配置互不干扰。constructor: 接收AxiosRequestConfig进行初始化。currentRequests: 用于实现全局 Loading 的计数器。只有当第一个请求开始时显示 Loading,所有请求完成后才隐藏 Loading,避免频繁闪烁。
setupInterceptors()方法:- 请求拦截器 (
request.use):showLoading控制:根据config.showLoading决定是否显示 Loading。needToken控制:根据config.needToken决定是否从localStorage中获取 Token 并添加到Authorization头。- 错误处理:在请求发送前的错误(如网络问题)会在这里被捕获。
- 响应拦截器 (
response.use):hideLoading控制:请求完成后隐藏 Loading。- 统一业务码处理:检查
response.data.code是否为200(BackendResponse类型)。若不是,则根据业务错误码进行处理(例如 401 跳转登录),并通过Promise.reject(data)抛出业务错误。这样,业务代码只需.catch处理实际的业务错误。 - HTTP 状态码处理:捕获服务器返回的非 2xx 状态码错误,根据
error.response.status进行分类处理和提示。 showErrorMessage控制:根据config.showErrorMessage决定是否显示错误提示。
- 请求拦截器 (
request()核心方法:- 使用泛型
<T = any, R = any>定义响应数据类型T和请求参数类型R,增强类型安全性。 - 返回
Promise<T>,即只返回BackendResponse中的data部分,简化业务层对数据的直接使用。 - 统一设置默认
Content-Type。
- 使用泛型
常用 HTTP 方法封装:
get,post,put,delete都是基于request()方法的便捷封装,进一步简化调用。取消请求:暴露
axios.CancelToken和axios.isCancel静态方法,方便业务层实现请求取消逻辑。默认实例导出:导出一个默认的
HttpRequest实例,方便全局直接使用。同时,也演示了如何创建和导出具有不同配置的多个实例。
五、进阶思考与扩展
- 文件上传下载:对于文件上传,需要将
Content-Type设置为multipart/form-data。对于文件下载,需要处理responseType和 Blob 数据。 - 错误重试机制:可以集成
axios-retry等库,在请求失败时自动重试。 - Token 刷新机制:当 401 错误发生时,判断是否存在 Refresh Token,然后静默刷新 Access Token,并重试之前的请求。
- 缓存策略:对于某些不经常变动的数据,可以在拦截器中实现简单的客户端缓存。
- 国际化 (i18n):错误提示信息可以根据当前语言环境进行国际化。
- 多个 API 前缀:在
baseURL基础上,支持更灵活的 API 前缀配置。 - Sentry/日志上报:在错误拦截器中将错误信息上报到错误监控系统。
- Loading 组件集成:将
showLoading和hideLoading替换为实际的组件库 Loading 弹窗/进度条。
六、总结
通过 TypeScript 封装 Axios 成通用工具类,是现代前端项目中的一种常见且极其推荐的实践。它不仅解决了重复配置、错误处理不统一等问题,还通过 TypeScript 提供了强大的类型安全保障,避免了在开发和运行时可能出现的类型错误。这使得项目的 HTTP 请求逻辑更加清晰、健壮、易于维护和扩展,极大地提升了团队的开发效率和项目的整体质量。
