Axios 取消请求

'# Axios 取消请求

一、背景与问题

在现代 Web 应用开发中,频繁的 API 请求是常态。但当用户快速切换操作时,可能会产生大量未完成的请求,导致资源浪费和性能下降。例如,用户在搜索框中连续输入多个关键词时,前一次的请求可能还未完成,此时若不主动取消,就会产生冗余请求。

Axios 提供了取消请求的机制,通过 CancelToken 和 AbortController 实现请求的主动中断。但其原理和使用场景需要深入理解,本文将从底层机制到实际应用进行深度解析。

二、基本原理

Axios 的取消请求机制基于浏览器原生的 AbortController API,通过以下步骤实现请求中断:

  1. 创建 AbortController 实例
  2. 通过 signal 属性将取消控制权传递给请求
  3. 在需要取消时调用 abort() 方法
  4. 服务器端通过 Connection: close 头终止连接(HTTP/1.1)

关键点:

  • HTTP 协议本身不支持取消请求,Axios 通过 AbortController 在客户端主动终止 TCP 连接
  • 服务器端可能不会响应中断请求(需具体实现支持)
  • 请求取消后,会触发 AbortError 异常

三、环境准备

确保项目中已安装 Axios:

npm install axios

四、核心实现

1. 基础用法(推荐方式)

// 创建取消控制器
const controller = new AbortController();

// 发起请求
axios.get('/api/data', {
  signal: controller.signal
})
.then(response => {
  console.log('成功:', response.data);
})
.catch(error => {
  if (error.name === 'AbortError') {
    console.log('请求已取消');
  } else {
    console.error('请求失败:', error.message);
  }
});

// 3秒后取消请求
setTimeout(() => {
  controller.abort();
}, 3000);

关键代码解释:

  • AbortController 创建信号控制对象
  • signal 属性绑定到请求配置
  • controller.abort() 发送中断信号
  • AbortError 区分普通错误和取消错误

2. 使用 CancelToken(旧版方式)

const source = axios.CancelToken.source();

axios.get('/api/data', {
  cancelToken: source.token
})
.then(response => {
  console.log('成功:', response.data);
})
.catch(error => {
  if (axios.isCancel(error)) {
    console.log('请求已取消');
  } else {
    console.error('请求失败:', error.message);
  }
});

// 3秒后取消请求
setTimeout(() => {
  source.cancel('用户主动取消请求');
}, 3000);

关键区别:

  • CancelToken 需要手动管理取消源
  • AbortController 是原生 API,支持更细粒度控制
  • AbortError 是原生错误类型,而 CancelToken 会抛出 Cancel 类型的错误

3. 带超时的取消策略

const controller = new AbortController();

axios.get('/api/data', {
  signal: controller.signal,
  timeout: 5000 // 5秒超时
})
.then(response => {
  console.log('成功:', response.data);
})
.catch(error => {
  if (error.name === 'AbortError') {
    console.log('请求已取消或超时');
  } else {
    console.error('请求失败:', error.message);
  }
});

// 3秒后取消请求
setTimeout(() => {
  controller.abort();
}, 3000);

性能优化点:

  • 超时机制可避免等待无效响应
  • 结合取消策略可避免资源浪费
  • 需注意超时时间与取消间隔的合理设置

五、完整案例

React 组件示例:搜索请求取消

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function SearchComponent() {
  const [results, setResults] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    let controller = new AbortController();

    const fetchData = async () => {
      setIsLoading(true);
      try {
        const response = await axios.get('/api/search', {
          signal: controller.signal,
          params: { query: 'test' }
        });
        setResults(response.data);
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('请求已取消');
        } else {
          console.error('请求失败:', error.message);
        }
      } finally {
        setIsLoading(false);
      }
    };

    fetchData();

    // 清理函数:组件卸载时取消请求
    return () => {
      controller.abort();
    };
  }, []);

  return (
    <div>
      <h2>搜索结果</h2>
      {isLoading && <p>加载中...</p>}
      <ul>
        {results.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

关键点:

  • 使用 useEffect 管理请求生命周期
  • 在清理函数中主动取消请求
  • 处理 AbortError 与普通错误的区别
  • 避免组件卸载时遗留未完成请求

六、源码解析

Axios 的取消机制在 src/axios.js 中实现,关键代码如下:

function createInstance() {
  const instance = axios.create();
  
  // 重写 request 方法
  instance.request = function(config) {
    const signal = config.signal;
    
    if (signal && signal.aborted) {
      throw new axios.Cancel('Request aborted');
    }
    
    // 原生 AbortController 实现
    if (signal instanceof AbortController) {
      signal.signal.addEventListener('abort', () => {
        config.onDownloadProgress?.({ aborted: true });
        config.onUploadProgress?.({ aborted: true });
      });
    }
    
    return instance._request(config);
  };
  
  return instance;
}

关键机制:

  • 检查 signal 是否被中止
  • 监听 abort 事件触发进度回调
  • 在底层使用 XMLHttpRequest 或 fetch 时处理中断

七、进阶使用

1. 多请求取消管理

const controller = new AbortController();

// 三个并发请求
axios.get('/api/data1', { signal: controller.signal })
  .catch(() => {});
  
axios.get('/api/data2', { signal: controller.signal })
  .catch(() => {});
  
axios.get('/api/data3', { signal: controller.signal })
  .catch(() => {});

// 5秒后取消所有请求
setTimeout(() => {
  controller.abort();
}, 5000);

2. 结合 Vue 路由守卫

router.beforeEach((to, from, next) => {
  // 取消当前页面的请求
  if (window.cancelToken) {
    window.cancelToken.abort();
  }
  next();
});

3. 自定义取消管理器

class CancelManager {
  constructor() {
    this.controllers = new Map();
  }
  
  createToken() {
    const controller = new AbortController();
    this.controllers.set(Date.now(), controller);
    return controller.signal;
  }
  
  cancelAll() {
    this.controllers.forEach(controller => {
      controller.abort();
    });
  }
}

八、性能与工程实践

1. 性能优化策略

  • 批量取消:避免频繁创建 AbortController 实例
  • 缓存信号:复用已有 controller 实例
  • 超时控制:设置合理的请求超时时间
  • 资源清理:在组件卸载或路由切换时主动取消

2. 异常处理规范

try {
  await axios.get('/api/data', { signal: controller.signal });
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('请求已取消');
  } else if (error.response) {
    console.error('服务器响应错误:', error.response.status);
  } else {
    console.error('网络错误:', error.message);
  }
}

3. 安全注意事项

  • 避免敏感数据泄露:取消请求时注意清理缓存
  • 防止滥用:限制取消请求的频率
  • 服务器端支持:确保后端能正确处理中断请求

九、常见问题与踩坑

1. 常见错误

错误示例:

const controller = new AbortController();
axios.get('/api/data', { signal: controller.signal });
controller.abort(); // 顺序错误

问题分析:在发送请求前就调用 abort() 会导致请求未发送就被取消

解决方案:确保在请求发送后才调用 abort()

2. 跨域问题

错误场景:某些服务器不支持 abort 请求,可能导致无法取消

解决方案:增加 Connection: close 头,强制服务器关闭连接

3. 记忆泄漏

错误场景:未正确清理控制器导致内存占用

解决方案:在组件卸载或路由切换时主动调用 abort()

十、最佳实践

1. 推荐方案

  • 使用 AbortController 替代旧版 CancelToken
  • 在用户输入时取消之前的搜索请求
  • 在组件卸载时清理所有未完成的请求
  • 在 API 调用前检查是否需要取消

2. 使用场景

  • 用户快速点击按钮时
  • 页面导航时
  • 输入框输入时
  • 超时未响应时

3. 不推荐场景

  • 必须完成的支付确认
  • 上传文件时(可能丢失数据)
  • 需要服务器端确认的业务操作

十一、总结

Axios 的取消请求机制是现代 Web 开发中避免资源浪费的重要手段。通过 AbortController 实现的主动中断,结合合理的使用场景,可以显著提升应用性能和用户体验。但在使用过程中需注意:避免在未发送请求时调用 abort(),确保服务器端支持中断操作,以及在组件卸载时进行清理。

实际开发中,建议结合具体业务场景选择适合的取消策略,例如在输入框中使用节流+取消,或在导航时使用全局取消管理。同时,注意处理各种异常情况,确保应用的健壮性。通过合理使用取消请求,可以有效提升应用的响应速度和资源利用率。

ios
最后修改于:2026年10月08日 04:05

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日