使用 Axios 和 AbortController 实现请求控制和取消

在现代 Web 开发中,处理异步请求是一个常见的需求。特别是在处理长时间运行的请求或需要取消未完成的请求时,使用 AbortController 可以帮助我们更好地控制和管理这些请求。本文将介绍如何结合 Axios 和 AbortController 实现请求控制和取消功能。

什么是 AbortController?

AbortController 是一个用于控制和取消 Web 请求的接口。它允许你在需要时中止一个或多个请求。AbortControllerAbortSignal 是 Fetch API 的一部分,主要用于取消正在进行的 fetch 请求,但也可以用于其他异步操作。

Axios 类型定义

在 TypeScript 中,使用 Axios 时,我们可以利用其提供的类型定义来进行类型检查和代码提示。以下是一些常用的 Axios 类型定义:

  • AxiosInstance :表示 Axios 实例的类型。包含 Axios 实例上的所有方法和属性,如 getpostrequest 等。
  • AxiosRequestConfig :表示 Axios 请求配置的类型。包含请求的所有配置选项,如 urlmethodheadersparamsdata 等。
  • AxiosResponse :表示 Axios 响应的类型。包含响应的所有属性,如 datastatusstatusTextheadersconfig 等。
  • CreateAxiosDefaults:包含创建 Axios 实例时的所有默认配置选项。
  • InternalAxiosRequestConfig:表示 Axios 内部请求配置的类型。包含 Axios 内部使用的请求配置选项,通常不需要在外部代码中直接使用。

实现步骤

我们将通过以下步骤实现请求控制和取消功能:

  1. 创建一个 AbortController 实例,并将其与请求关联。
  2. 使用 Axios 请求拦截器将 AbortSignal 传递给请求。
  3. 使用 Axios 响应拦截器在请求完成后移除 AbortController
  4. 提供方法来取消特定请求或所有请求。

代码实现

1. 安装 Axios 和 TypeScript

首先,确保你已经安装了 Axios 和 TypeScript:

bash 复制代码
npm install axios
npm install typescript

2. 创建 RequestController 类

typescript 复制代码
import axios, {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  CreateAxiosDefaults,
  InternalAxiosRequestConfig,
} from 'axios';

class RequestController {
  private instance: AxiosInstance;
  private abortControllerMap: Map<string, AbortController>;

  constructor(config?: CreateAxiosDefaults) {
    this.instance = axios.create(config);
    this.abortControllerMap = new Map();
    this.setupInterceptors();
  }

  private setupInterceptors() {
    // 请求拦截器
    this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
      const controller = new AbortController();
      config.signal = controller.signal; // 挂载控制器的发射器
      const url = config.url || '';
      this.abortControllerMap.set(url, controller); // 添加控制器进入 map
      return config;
    });

    // 响应拦截器
    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        const url = response.config.url || '';
        this.abortControllerMap.delete(url); // 删除 map 里的本条数据
        return response;
      },
      (error) => {
        const url = error.config.url || '';
        this.abortControllerMap.delete(url); // 删除 map 里的本条数据
        return Promise.reject(error);
      }
    );
  }

  // 取消指定请求
  public cancelRequest(url: string) {
    const controller = this.abortControllerMap.get(url);
    if (controller) {
      controller.abort(); // 使用控制器终止请求
      this.abortControllerMap.delete(url); // 删除 map 里的本条数据
    }
  }

  // 取消所有请求
  public cancelAllRequests() {
    for (const [, controller] of this.abortControllerMap) {
      controller.abort(); // 使用控制器终止请求
    }
    this.abortControllerMap.clear(); // 清空请求列表
  }

  // 发起请求
  public request<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.instance.request(config);
  }
}

export default new RequestController();

解释

  1. 导入部分:

    typescript 复制代码
    import axios, {
      AxiosInstance,
      AxiosRequestConfig,
      AxiosResponse,
      CreateAxiosDefaults,
      InternalAxiosRequestConfig,
    } from 'axios';
    • 导入 Axios 库和相关类型定义。
  2. 定义类和私有属性:

    typescript 复制代码
    class RequestController {
      private instance: AxiosInstance;
      private abortControllerMap: Map<string, AbortController>;
    
      constructor(config?: CreateAxiosDefaults) {
        this.instance = axios.create(config);
        this.abortControllerMap = new Map();
        this.setupInterceptors();
      }
    }
    • 定义 RequestController 类。
    • 使用 private 关键字定义私有属性 instanceabortControllerMap
    • instance 是一个 Axios 实例,用于发起 HTTP 请求。
    • abortControllerMap 是一个 Map,用于存储每个请求的 AbortController
  3. 设置拦截器:

    typescript 复制代码
    private setupInterceptors() {
      // 请求拦截器
      this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
        const controller = new AbortController();
        config.signal = controller.signal; // 挂载控制器的发射器
        const url = config.url || '';
        this.abortControllerMap.set(url, controller); // 添加控制器进入 map
        return config;
      });
    
      // 响应拦截器
      this.instance.interceptors.response.use(
        (response: AxiosResponse) => {
          const url = response.config.url || '';
          this.abortControllerMap.delete(url); // 删除 map 里的本条数据
          return response;
        },
        (error) => {
          const url = error.config.url || '';
          this.abortControllerMap.delete(url); // 删除 map 里的本条数据
          return Promise.reject(error);
        }
      );
    }
    • 在请求拦截器中,创建一个 AbortController 实例,并将其 signal 传递给请求配置。
    • 在响应拦截器中,请求完成后移除 AbortController
  4. 取消指定请求:

    typescript 复制代码
    public cancelRequest(url: string) {
      const controller = this.abortControllerMap.get(url);
      if (controller) {
        controller.abort(); // 使用控制器终止请求
        this.abortControllerMap.delete(url); // 删除 map 里的本条数据
      }
    }
    • 提供 cancelRequest 方法,用于取消特定请求。
  5. 取消所有请求:

    typescript 复制代码
    public cancelAllRequests() {
      for (const [, controller] of this.abortControllerMap) {
        controller.abort(); // 使用控制器终止请求
      }
      this.abortControllerMap.clear(); // 清空请求列表
    }
    • 提供 cancelAllRequests 方法,用于取消所有请求。
  6. 发起请求:

    typescript 复制代码
    public request<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
      return this.instance.request(config);
    }
    • 提供 request 方法,用于发起 HTTP 请求。

使用示例

下面是一个使用 RequestController 类的示例,展示了如何发起请求和取消请求。

typescript 复制代码
import RequestController from './RequestController';

// 发起请求
RequestController.request({
  url: 'https://jsonplaceholder.typicode.com/posts',
  method: 'GET',
})
  .then((response) => {
    console.log('Response:', response.data);
  })
  .catch((error) => {
    if (error.name === 'AbortError') {
      console.log('Request aborted');
    } else {
      console.error('Request error:', error);
    }
  });

// 取消特定请求
RequestController.cancelRequest('https://jsonplaceholder.typicode.com/posts');

// 取消所有请求
RequestController.cancelAllRequests();

总结

通过结合 Axios 和 AbortController,我们可以实现对请求的精细控制和管理。本文介绍了如何在 TypeScript 中使用 private 关键字定义一个私有的 Axios 实例属性,并结合 AbortController 实现请求控制和取消功能。希望这篇文章对你有所帮助,让你在处理异步请求时更加得心应手。

如果你有任何问题或建议,欢迎在评论区留言讨论。谢谢阅读!

相关推荐
猫头虎1 小时前
如何解决IDE项目启动报错 error:0308010C:digital envelope routines::unsupported 问题
javascript·ide·vue.js·typescript·node.js·编辑器·vim
FanetheDivine3 小时前
three.js学习笔记 2.光照和材质
react.js·three.js
PyAIGCMaster5 小时前
穷鬼计划:react+tailwindcss+vercel
前端·react.js·前端框架
啵咿傲7 小时前
Next框架学习篇 ✅
react.js·服务端渲染
JiangJiang19 小时前
🚀 React 弹窗还能这样写?手撸一个高质量 Modal 玩起来!
前端·javascript·react.js
t20071819 小时前
4.27 react第一天
前端·react.js·前端框架
parade岁月20 小时前
TypeScript 全局类型声明文件规范性分析与归纳
前端·vue.js·typescript
溪i20 小时前
react-spring/web + children not defined
前端·spring·react.js
egghead2631620 小时前
trae+react+tailwindcss项目开发
前端·react.js