TypeScript利用TS封装Axios实战

目录
  • 简介
  • Axios几个常用类型
    • AxiosRequestConfig
    • AxiosInstance
    • AxiosStatic
    • AxiosResponse
    • AxiosError
  • 基础封装
  • 拦截器封装
  • 常用方法封装
  • 总结

简介

这是TypeScript实战的第三篇文章。前面两篇笔者分别介绍了在Vuex和Pinia中怎么使用TypeScript以及VuexPinia的区别。今天我们再用TypeScript封装一遍Axios。希望能进一步巩固TypeScript的基础知识。

Axios几个常用类型

在使用TypeScript封装Axios之前我们先来看看Axios几个重要的类型。

AxiosRequestConfig

AxiosRequestConfig是我们使用axios发送请求传递参数的类型。当然它也是我们请求拦截器里面的参数类型。

axios(config: AxiosRequestConfig)

可以看到,这个config里面的参数还是挺多的。我们常用的有url、method、params、data、headers、baseURL、timeout

export interface AxiosRequestConfig {
  url?: string;
  method?: Method;
  baseURL?: string;
  transformRequest?: AxiosTransformer | AxiosTransformer[];
  transformResponse?: AxiosTransformer | AxiosTransformer[];
  headers?: any;
  params?: any;
  paramsSerializer?: (params: any) => string;
  data?: any;
  timeout?: number;
  timeoutErrorMessage?: string;
  withCredentials?: boolean;
  adapter?: AxiosAdapter;
  auth?: AxiosBasicCredentials;
  responseType?: ResponseType;
  xsrfCookieName?: string;
  xsrfHeaderName?: string;
  onUploadProgress?: (progressEvent: any) => void;
  onDownloadProgress?: (progressEvent: any) => void;
  maxContentLength?: number;
  validateStatus?: ((status: number) => boolean) | null;
  maxBodyLength?: number;
  maxRedirects?: number;
  socketPath?: string | null;
  httpAgent?: any;
  httpsAgent?: any;
  proxy?: AxiosProxyConfig | false;
  cancelToken?: CancelToken;
  decompress?: boolean;
  transitional?: TransitionalOptions
}

AxiosInstance

AxiosInstance是我们使用axios实例对象类型。

我们使用axios.create(config?: AxiosRequestConfig)创建出来的对象都是AxiosInstance类型

export interface AxiosInstance {
  (config: AxiosRequestConfig): AxiosPromise;
  (url: string, config?: AxiosRequestConfig): AxiosPromise;
  defaults: AxiosRequestConfig;
  interceptors: {
    request: AxiosInterceptorManager<AxiosRequestConfig>;
    response: AxiosInterceptorManager<AxiosResponse>;
  };
  getUri(config?: AxiosRequestConfig): string;
  request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>;
  get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
  delete<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
  head<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
  options<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
  post<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
  put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
  patch<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
}

可以发现,我们可以使用axios.create、axios.all、axios.spread方法,但是AxiosInstance 上并没有create、all、spread等方法,那我们的axios到底是什么类型呢?

AxiosStatic

export interface AxiosStatic extends AxiosInstance {
  create(config?: AxiosRequestConfig): AxiosInstance;
  Cancel: CancelStatic;
  CancelToken: CancelTokenStatic;
  isCancel(value: any): boolean;
  all<T>(values: (T | Promise<T>)[]): Promise<T[]>;
  spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
  isAxiosError(payload: any): payload is AxiosError;
}
declare const axios: AxiosStatic;

可以发现,axios其实是AxiosStatic类型,并且继承了AxiosInstance类型。所以是两者的结合。相较axios.create(config?: AxiosRequestConfig)创建出来的实例对象,axios功能是更强大的。

AxiosResponse

AxiosResponse是非常重要的,我们的axios请求返回值类型都是AxiosResponse类型。并且我们可以发现AxiosResponse是一个接口泛型,这个泛型会应用到后端返回的data上。所以这块我们可以根据后端接口返回定义不同的类型传递进去。后面笔者在封装常用方法的时候会细说。

export interface AxiosResponse<T = any>  {
  data: T;
  status: number;
  statusText: string;
  headers: any;
  config: AxiosRequestConfig;
  request?: any;
}

AxiosError

AxiosError这个类型也是我们必须要知道的。在我们响应拦截器里面的错误就是AxiosError类型。

export interface AxiosError<T = any> extends Error {
  config: AxiosRequestConfig;
  code?: string;
  request?: any;
  response?: AxiosResponse<T>;
  isAxiosError: boolean;
  toJSON: () => object;
}

说完了Axios的几个常用类型,接下来我们正式开始使用TS来封装我们的Axios

基础封装

首先我们实现一个最基本的版本,实例代码如下:

// index.ts
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

class Request {
  // axios 实例
  instance: AxiosInstance
  // 基础配置,url和超时时间
  baseConfig: AxiosRequestConfig = {baseURL: "/api", timeout: 60000}

  constructor(config: AxiosRequestConfig) {
    // 使用axios.create创建axios实例
    this.instance = axios.create(Object.assign(this.baseConfig, config))
  }
  // 定义请求方法
  public request(config: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.instance.request(config)
  }
}
export default Request

在实际项目中有了基本的请求方法还是远远不够的,我们还需要封装拦截器和一些常用方法。

拦截器封装

拦截器封装只需要在类中对axios.create()创建的实例调用interceptors下的两个拦截器即可,

实例代码如下:

// index.ts
constructor(config: AxiosRequestConfig) {
  this.instance = axios.create(Object.assign(this.baseConfig, config))
  this.instance.interceptors.request.use(
    (config: AxiosRequestConfig) => {
      // 一般会请求拦截里面加token
      const token = localStorage.getItem("token")
      config.headers["Authorization"] = token;

      return config
    },
    (err: any) => {
      return Promise.reject(err)
    },
  )
  this.instance.interceptors.response.use(
    (res: AxiosResponse) => {
      // 直接返回res,当然你也可以只返回res.data
      return res
    },
    (err: any) => {
      // 这里用来处理http常见错误,进行全局提示
      let message = "";
      switch (err.response.status) {
        case 400:
          message = "请求错误(400)";
          break;
        case 401:
          message = "未授权,请重新登录(401)";
          // 这里可以做清空storage并跳转到登录页的操作
          break;
        case 403:
          message = "拒绝访问(403)";
          break;
        case 404:
          message = "请求出错(404)";
          break;
        case 408:
          message = "请求超时(408)";
          break;
        case 500:
          message = "服务器错误(500)";
          break;
        case 501:
          message = "服务未实现(501)";
          break;
        case 502:
          message = "网络错误(502)";
          break;
        case 503:
          message = "服务不可用(503)";
          break;
        case 504:
          message = "网络超时(504)";
          break;
        case 505:
          message = "HTTP版本不受支持(505)";
          break;
        default:
          message = `连接出错(${err.response.status})!`;
      }
      // 这里错误消息可以使用全局弹框展示出来
      // 比如element plus 可以使用 ElMessage
      ElMessage({
        showClose: true,
        message: `${message},请检查网络或联系管理员!`,
        type: "error",
      });
      // 这里是AxiosError类型,所以一般我们只reject我们需要的响应即可
      return Promise.reject(err.response)
    },
  )
}

在这里我们分别对请求拦截器和响应拦截器做了处理。在请求拦截器我们给请求头添加了token

在响应拦截器,我们返回了整个response对象,当然你也可以只返回后端返回的response.data,这里可以根据个人喜好来处理。其次对http错误进行了全局处理。

常用方法封装

在基础封装的时候我们封装了一个request通用方法,其实我们还可以更具体的封装get、post、put、delete方法,让我们使用更方便。

并且,我们前面分析到,AxiosResponse其实是一个泛型接口,他可以接受一个泛型并应用到我们的data上。所以我们可以在这里再定义一个后端通用返回的数据类型。

比如假设我们某个项目后端接口不管请求成功与失败,返回的结构永远是code、message、results的话我们可以定义一个这样的数据类型。

type Result<T> = {
  code: number,
  message: string,
  result: T
}

然后传递个各个方法:

public get<T = any>(
  url: string,
  config?: AxiosRequestConfig
): Promise<AxiosResponse<Result<T>>> {
  return this.instance.get(url, config);
}
public post<T = any>(
  url: string,
  data?: any,
  config?: AxiosRequestConfig
): Promise<AxiosResponse<Result<T>>> {
  return this.instance.post(url, data, config);
}
public put<T = any>(
  url: string,
  data?: any,
  config?: AxiosRequestConfig
): Promise<AxiosResponse<Result<T>>> {
  return this.instance.put(url, data, config);
}
public delete<T = any>(
  url: string,
  config?: AxiosRequestConfig
): Promise<AxiosResponse<Result<T>>> {
  return this.instance.delete(url, config);
}

这样当我们调用接口的时候就可以看到我们返回的data的类型啦。就是我们定义的Result类型。

所以我们可以直接得到自动提示:

上面调用接口的时候并没有传递接口数据类型,所以我们的resultany类型,要想要每个接口都有类型提示,我们还需要给方法传递泛型。

我们再改进下,我们再定义一个login接口返回值类型loginType

type loginType = {
  token: string;
};

然后再调用方法的地方传递进去,然后我们再看看返回值data的类型。

可以看到他是Result<loginType>类型,这个loginType就是result的类型。

所以我们的result还可以进一步的得到提示

当然每个接口都定义返回值类型固然好,但是会大大加大前端的工作量。我们在写请求方法的时候也可以不传递接口返回值类型,这样result的类型就是any。这个可以根据自身项目需求来选择使用。

看到这小伙伴们是不是都弄懂了呢?如还有疑问欢迎留言。

总结

说了这么多,有些小伙伴们可能有点晕了,下面笔者总结下整个axios的封装。

// index.ts
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
type Result<T> = {
  code: number;
  message: string;
  result: T;
};
class Request {
  // axios 实例
  instance: AxiosInstance;
  // 基础配置,url和超时时间
  baseConfig: AxiosRequestConfig = { baseURL: "/api", timeout: 60000 };

  constructor(config: AxiosRequestConfig) {
    // 使用axios.create创建axios实例
    this.instance = axios.create(Object.assign(this.baseConfig, config));

    this.instance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        // 一般会请求拦截里面加token
        const token = localStorage.getItem("token");
        config.headers["Authorization"] = token;

        return config;
      },
      (err: any) => {
        return Promise.reject(err);
      }
    );

    this.instance.interceptors.response.use(
      (res: AxiosResponse) => {
        // 直接返回res,当然你也可以只返回res.data
        return res;
      },
      (err: any) => {
        // 这里用来处理http常见错误,进行全局提示
        let message = "";
        switch (err.response.status) {
          case 400:
            message = "请求错误(400)";
            break;
          case 401:
            message = "未授权,请重新登录(401)";
            // 这里可以做清空storage并跳转到登录页的操作
            break;
          case 403:
            message = "拒绝访问(403)";
            break;
          case 404:
            message = "请求出错(404)";
            break;
          case 408:
            message = "请求超时(408)";
            break;
          case 500:
            message = "服务器错误(500)";
            break;
          case 501:
            message = "服务未实现(501)";
            break;
          case 502:
            message = "网络错误(502)";
            break;
          case 503:
            message = "服务不可用(503)";
            break;
          case 504:
            message = "网络超时(504)";
            break;
          case 505:
            message = "HTTP版本不受支持(505)";
            break;
          default:
            message = `连接出错(${err.response.status})!`;
        }
        // 这里错误消息可以使用全局弹框展示出来
        // 比如element plus 可以使用 ElMessage
        ElMessage({
          showClose: true,
          message: `${message},请检查网络或联系管理员!`,
          type: "error",
        });
        // 这里是AxiosError类型,所以一般我们只reject我们需要的响应即可
        return Promise.reject(err.response);
      }
    );
  }

  // 定义请求方法
  public request(config: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.instance.request(config);
  }

  public get<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<Result<T>>> {
    return this.instance.get(url, config);
  }
  public post<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<Result<T>>> {
    return this.instance.post(url, data, config);
  }
  public put<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<Result<T>>> {
    return this.instance.put(url, data, config);
  }

  public delete<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<Result<T>>> {
    return this.instance.delete(url, config);
  }
}
export default Request;

到此这篇关于TypeScript利用TS封装Axios实战的文章就介绍到这了,更多相关TypeScript封装Axios内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue+Typescript中在Vue上挂载axios使用时报错问题

    在vue项目开发过程中,为了方便在各个组件中调用axios,我们通常会在入口文件将axios挂载到vue原型身上,如下: main.ts import Vue from 'vue' import axios from './utils/http' Vue.prototype.$axios = axios; 这样的话,我们在各个组件中进行请求时,就可以直接使用this.$axios,但是在ts中使用this.$axios进行请求时,会进行报错,如下所示: 从图中我们可以看出ts在Vue身上检测不到

  • 基于Typescript与Axios的接口请求管理详解

    目录 思路 请求拦截 响应拦截 使用httpClient.ts定义请求 在组件中请求接口 总结 本文主要介绍基于TS和AXIOS的接口请求封装 思路 请求拦截 在请求头添加一些参数,例如token,uid等 判断用户登录状态,如果没有登录,直接跳转登录 处理请求数据转换发送请求的数据格式,json→urlencoded (可选的) 响应拦截 判断后端响应的业务状态码,进行不同的处理 例如用户登录状态过期,直接跳转登录 统一的报错提示 先把套路化的代码写出来: import axios, { Ax

  • Vue3中使用typescript封装axios的实例详解

    这个axios封装,因为是用在vue3的demo里面的,为了方便,在vue3的配置里面按需加载element-plus 封装axios http.ts import axios, { AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse } from 'axios' import { IResponseData } from '@/types' import { ElMessage, ElLoading, ILoadingInstance

  • Vue3+TypeScript封装axios并进行请求调用的实现

    不是吧,不是吧,原来真的有人都2021年了,连TypeScript都没听说过吧?在项目中使用TypeScript虽然短期内会增加一些开发成本,但是对于其需要长期维护的项目,TypeScript能够减少其维护成本,使用TypeScript增加了代码的可读性和可维护性,且拥有较为活跃的社区,当居为大前端的趋势所在,那就开始淦起来吧~ 使用TypeScript封装基础axios库 代码如下: // http.ts import axios, { AxiosRequestConfig, AxiosRes

  • TypeScript利用TS封装Axios实战

    目录 简介 Axios几个常用类型 AxiosRequestConfig AxiosInstance AxiosStatic AxiosResponse AxiosError 基础封装 拦截器封装 常用方法封装 总结 简介 这是TypeScript实战的第三篇文章.前面两篇笔者分别介绍了在Vuex和Pinia中怎么使用TypeScript以及Vuex和Pinia的区别.今天我们再用TypeScript封装一遍Axios.希望能进一步巩固TypeScript的基础知识. Axios几个常用类型 在

  • 项目中使用Typescript封装axios

    目录 写在前面 基础封装 拦截器封装 类拦截器 实例拦截器 接口拦截 封装请求方法 取消请求 准备工作 取消请求方法的添加与删除 取消请求方法 测试 测试请求方法 测试取消请求 写在最后 写在前面 虽然说Fetch API已经使用率已经非常的高了,但是在一些老的浏览器还是不支持的,而且axios仍然每周都保持2000多万的下载量,这就说明了axios仍然存在不可撼动的地位,接下来我们就一步一步的去封装,实现一个灵活.可复用的一个请求请发. 这篇文章封装的axios已经满足如下功能: 无处不在的代

  • 如何使用TS对axios的进行简单封装

    目录 1.安装axios 2.在合适路径下新建request.ts(名称可随意),例如可以在项目的src下创建utils文件夹创建request.ts 3.导入axios并创建axios实例 4.封装请求函数 ① 查看axios的类型声明文件 ② 请求配置对象的类型 ③ 响应对象的类型 ④ axios.request函数 ⑤ 开始封装 ⑥ 使用 总结 1.安装axios npm i axios 2.在合适路径下新建request.ts(名称可随意),例如可以在项目的src下创建utils文件夹创

  • 在项目中封装axios的实战过程

    目录 前言 axios封装的好处 封装思路 配置的优先顺序 axios实例配置 1.定义一些常规的配置 2.请求前加一些我们需要的操作, 3.请求返回后,添加拦截操作, 请求接口方法统一管理 最后放一下完整的示例!大家可以参考一下~ 总结 前言 在学习和做项目的时候经常会碰到axios,之前做的项目一般都是配置好axios,所以自己一直有个大概印象,最近有个机会自己可以手动配置axios,顺便记录分享一下~ axios封装的好处 axios封装的好处是统一处理,提高效率,便于维护. 你可以像下面

  • 一篇文章让你看懂封装Axios

    目录 前言 拦截器不要返回数据,依然返回 AxiosResponse 对象 不推荐的做法 推荐的做法 为你的请求添加拓展 支持请求重试 支持 jsonp 请求 支持 URI 版本控制 保持请求唯一 后语 总结 前言 看很多网上的人的封装 Axios 教程,但或多或少都有不太合适的点,这里为大家推荐我的最佳实践. 拦截器不要返回数据,依然返回 AxiosResponse 对象 网上的文章都让你用 拦截器 直接返回数据,这种作法其实是非常不妥的,这样会让你后续的功能很难进行拓展. 不推荐的做法 im

  • Vue项目中封装axios的方法

    目录 一.axios是什么 特性 基本使用 二.为什么要封装 三.如何封装 设置接口请求前缀 设置请求头与超时时间 封装请求方法 请求拦截器 响应拦截器 小结 参考文献 一.axios是什么 axios 是一个轻量的 HTTP客户端 基于 XMLHttpRequest 服务来执行 HTTP 请求,支持丰富的配置,支持 Promise,支持浏览器端和 Node.js 端.自Vue2.0起,尤大宣布取消对 vue-resource 的官方推荐,转而推荐 axios.现在 axios 已经成为大部分

  • 详解Vue 2.0封装axios笔记

    前言 单页面应用大多采用前后端分离开发思路,我们知道,前端和后端交互有多中方式(服务器端渲染.Ajax.websocket等),今天我们主要讲解Ajax部分. 最近团队讨论了一下,Ajax 本身跟 Vue 并没有什么需要特别整合的地方,使用 fetch polyfill 或是 axios.superagent 等等都可以起到同等的效果,vue-resource 提供的价值和其维护成本相比并不划算,所以决定在不久以后取消对 vue-resource 的官方推荐.已有的用户可以继续使用,但以后不再把

  • Vue二次封装axios为插件使用详解

    照例先贴上 axios的 gitHub 地址 不管用什么方式获取数据,对于一个项目来说,代码一定要利于维护其次是一定要写的优美,因此加上一层封装是必要的 vuejs2.0 已经不再维护 vue-resource,vuejs2.0 已经使用了 axios,这也是为什么我会转到 axios 的主要原因,废话不多说: 基本的封装要求: 统一 url 配置 统一 api 请求 request (请求)拦截器,例如:带上token等,设置请求头 response (响应)拦截器,例如:统一错误处理,页面重

随机推荐