【axios】TypeScript实战,结合源码,从0到1教你封装一个axios - 基础封装篇

本文详细介绍了如何在Vue3项目中使用TypeScript对axios进行基础封装,包括环境变量配置、axios实例类型、拦截器和CRUD操作的封装,以及文件上传的处理。

本文已入选 [2023-11-29]|优快云每天值得看|移动开发

前言

axios 是一个流行的网络请求库,简单易用。但实际上,我们开发时候经常会出于不同的需求对它进行各种程度的封装。

最近在制作自己的脚手架时,写了一个Vue3+ts+Vite项目模板,其中使用TypeScript对axios的基础请求功能进行了简单的封装,在这里梳理一下思路,也留作一个记录,为后续其他功能封装做准备。

希望这篇文章能够帮助到刚学习axios和ts的小伙伴们。同时,若文中存在一些错误或者设计不合理的地方,也欢迎大家指正。

版本

  • axios1.6.2
  • TypeScript5.3.2

环境变量配置

一般我们会使用环境变量来统一管理一些数据,比如网络请求的 baseURL 。这个项目模板中,我将文件上传的接口地址、token的key也配置在了环境变量里。

.env.development

# .env.production 和这个一样
# the APP baseURL
VITE_APP_BASE_URL = 'your_base_url'

# the token key
VITE_APP_TOKEN_KEY = 'your_token_key'

# the upload url
VITE_UPLOAD_URL = 'your_upload_url'

# app title
VITE_APP_TITLE = 'liushi_template'

环境变量类型声明文件 env.d.ts

/// <reference types="vite/client" />

export interface ImportMetaEnv {
   
   
    readonly VITE_APP_TITLE: string
    readonly VITE_APP_BASE_URL: string
    readonly VITE_APP_TOKEN_KEY?: string
    readonly VITE_UPLOAD_URL?: string
}

interface ImportMeta {
   
   
    readonly env: ImportMetaEnv
}

然后,我们使用 来封装 axios

先引入 axios, 以及必要的类型

import axios, 
    {
   
    AxiosInstance,
      InternalAxiosRequestConfig, 
      AxiosRequestConfig, 
      AxiosError, 
      AxiosResponse,
    } from 'axios';

在这里,我们引入了 axios,以及一些本次封装中会使用到的类型,

使用ts进行二次封装时,最好 ctrl+左键 看一下源码中对应的类型声明,这对我们有很大的帮助和指导作用。

引入的类型

1、AxiosIntance: axios实例类型

image.png

2、InternalAxiosRequestConfig: 高版本下AxiosRequestConfig的拓展类型

image.png

注意: 以前的版本下,请求拦截器的 use方法 第一个参数类型是 AxiosRequestConfig,但在高版本下,更改为了 InternalAxiosRequestConfig,如果发现使用 AxiosRequestConfig时报错, 请看一下自己版本下的相关类型声明。这里提供我的:

image.png

image.png

3、AxiosRequestConfig: 请求体配置参数类型

image.png

4、AxiosError: 错误对象类型

image.png

5、AxiosResponse: 完整原始响应体类型

image.png

从源码提供的类型可以很清晰地看到各参数或者类、方法中对应的参数、方法类型定义,这可以非常直观地为我们指明路线

目标效果

通过这次基础封装,我们想要的实现的效果是:

  • API的参数只填写接口和其他配置项、可以规定后端返回数据中 data 的类型
  • API直接返回后端返回的数据
  • 错误码由响应拦截器统一处理
  • 预留 扩展其他进阶功能的空间
  • nice的代码提示

开始封装

骨架

axios 和其中的类型在前面已经引入, 这里就先写一个骨架

class HttpRequest {
   
   
    service: AxiosInstance
    constructor(){
   
   
        // 设置一些默认配置项
        this.service = axios.create({
   
   
            baseURL: import.meta.env.VITE_APP_BASE_URL,
            timeout: 5 * 1000
        });
    }
}

const httpRequest = new HttpRequest()
export default httpRequest;

在拦截器封装之前

为了封装出更加合理的拦截器,为以及进阶封装时为 axios 配置更加强大的功能,你需要首先了解一下 axios 从发送一个请求到接收响应并处理,最后呈现给用户的流程。这样,对各部分的封装会有一个更加合理的设计。

image.png

axios请求流程 - chatGPT绘制

全局请求拦截器

class HttpRequest {
   
   
    // ...
    constructor() {
   
   
        // ...
        this.service.interceptors.request.use(
            // ...
        );
    }
}

axios v1.6.2 中,根据上面的接口请求拦截器的 use方法 接受三个参数, 均是可传项

image.png

  • onFulfilled: 在请求发送前执行, 接受一个 config 对象并返回处理后的新 config对象,一般在里面配置token等

    这里要注意一点, 高版本 axios 将它的参数类型修改为了 InternalAxiosRequestConfig

  • onRejected: onFulfilled 执行发生错误后执行,接收错误对象,一般我们请求没发送出去出现报错时,执行的就是这一步

  • options:其他配置参数,接收两个参数, 均是可传项,以后的进阶功能封装里可能会使用到

    • synchronous: 是否同步
    • runWhen: 接收一个类型为InternalAxiosRequestConfigconfig 参数,返回一个 boolean。触发时机为每次请求触发拦截器之前,runWhen返回 true, 则执行作用在本次请求上的拦截器方法, 否则不执行

了解了三个参数之后,思路就清晰了,然后我们可以根据需求进行全局请求拦截器的封装

class HttpRequest {
   
   
    // ...
    constructor() {
   
   
        // ...
        this.service.interceptors.request.use(
            (config: InternalAxiosRequestConfig) => {
   
   
                /**
                 * set your config
                 */
                if (import.meta.env.VITE_APP_TOKEN_KEY && getToken()) {
   
   
                    // carry token
                    config.headers[import.meta.env.VITE_APP_TOKEN_KEY] = getToken()
                }
                return config
            },
            (error: AxiosError) => {
   
   
                console.log('requestError: ', error)
                return Promise.reject(error);
            },
            {
   
   
                synchronous: false,
                runWhen: ((config: InternalAxiosRequestConfig) => {
   
   
                    // do something

                    // if return true, axios will execution interceptor method
                    return true
                })
            }
        );
    }
}

全局响应拦截器

同样是三个参数,后两个和请求拦截器差不多,说第一个就行。

类型定义如下:

image.png

第一个参数同样是 onFulfilled,在返回响应结果之前执行,我们需要在这里面取出后端返回的数据,同时还要进行状态码处理。

从类型定义上可以看到,参数类型是一个泛型接口, 第一个泛型 T 用来定义后端返回数据的类型

先定义一下和后端约定好的返回数据格式:

我一般做项目时候约定的是这种,可以根据实际情况进行修改

./types/index.ts

export interface ResponseModel<T = any> {
   
   
    success: boolean;
    message: string | null;
    code: number
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

六时二一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值