IOS浏览器中axios被中断时可以被catch到,在web以及android不可以

本文探讨了使用axios发送请求时,在安卓及web端遇到的请求中断无法通过Promise.prototype.catch()捕获的问题,特别是在浏览器URL跳转等情况下。有趣的是,这一问题在iOS环境下却能得到解决。


axios发送请求时,当发生浏览器url跳转或者其他未知原因使得请求中断时,
安卓以及web端使用Promise.prototype.catch()方法是捕获不到错误的,
但是ios环境下的浏览器都可以捕获到。








<think>我们正在讨论在Vue.js中使用Axios中断HTTP请求。根据之前提供的引用内容,我们知道在Vue中中断请求的场景包括:避免重复请求覆盖、组件卸载时取消请求等。下面我将结合Vue.js的特性,详细说明如何实现。 在Vue中,我们通常会在组件的生命周期钩子(如`created`或`mounted`)中发起请求。为了在组件卸载时取消请求,我们可以利用Vue的`beforeUnmount`(Vue 3)或`beforeDestroy`(Vue 2)生命周期钩子来执行取消操作。 ### 一、使用AbortController(推荐) #### 基本步骤: 1. 在组件中创建`AbortController`实例 2. 将`controller.signal`传递给axios请求的配置项 3. 在组件卸载前调用`controller.abort()`取消请求 #### Vue 3 示例(Composition API): ```vue <script setup> import { ref, onBeforeUnmount } from 'vue'; import axios from 'axios'; const data = ref(null); // 创建AbortController实例 const controller = new AbortController(); // 发起请求 axios.get('/api/data', { signal: controller.signal }) .then(response => data.value = response.data) .catch(err => { // 判断是否为取消请求导致的错误 if (axios.isCancel(err)) { console.log('请求被取消:', err.message); } else { // 处理其他错误 } }); // 组件卸载前取消请求 onBeforeUnmount(() => { controller.abort('组件卸载,取消请求'); }); </script> ``` #### Vue 2 示例(Options API): ```javascript export default { data() { return { data: null, controller: null }; }, created() { // 创建控制器 this.controller = new AbortController(); axios.get('/api/data', { signal: this.controller.signal }) .then(res => this.data = res.data) .catch(err => { if (axios.isCancel(err)) { console.log('请求取消:', err.message); } }); }, beforeDestroy() { // 组件销毁前取消请求 if (this.controller) { this.controller.abort('组件销毁'); } } } ``` ### 二、使用全局请求列表管理(适用于多个请求) 引用[2]中提到了一种全局管理请求的方案:在Vue原型上挂载一个请求列表,每次发起请求时将请求的取消方法存入列表,在需要取消时遍历列表执行取消操作。 #### 实现步骤(以Vue 3为例): 1. 在`main.js`中全局挂载请求列表 2. 在请求拦截器中添加请求到列表 3. 在响应拦截器中移除已完成请求 4. 提供全局取消方法 ```javascript // main.js import { createApp } from 'vue'; import App from './App.vue'; import axios from 'axios'; const app = createApp(App); // 全局请求列表 app.config.globalProperties.$httpRequestList = new Set(); // 请求拦截器 axios.interceptors.request.use(config => { const controller = new AbortController(); config.signal = controller.signal; // 将取消方法添加到全局列表 app.config.globalProperties.$httpRequestList.add(controller); return config; }); // 响应拦截器(成功和失败都要移除) axios.interceptors.response.use( response => { // 从全局列表中移除 const controller = response.config.controller; if (controller) { app.config.globalProperties.$httpRequestList.delete(controller); } return response; }, error => { if (axios.isCancel(error)) { // 如果是取消请求,报错,直接返回一个空对象 return Promise.reject({ isCanceled: true }); } // 其他错误处理 return Promise.reject(error); } ); app.mount('#app'); ``` #### 组件内使用: ```vue <script setup> import { getCurrentInstance, onBeforeUnmount } from 'vue'; const { proxy } = getCurrentInstance(); // 发起请求 axios.get('/api/data').then(res => { console.log(res.data); }); // 组件卸载时取消所有请求 onBeforeUnmount(() => { proxy.$httpRequestList.forEach(controller => controller.abort()); proxy.$httpRequestList.clear(); }); </script> ``` ### 三、特定场景:中断重复请求 在搜索框等场景中,我们需要中断上一次未完成的请求,以保证获取最新结果。 #### 实现思路: 1. 为每个请求类型创建唯一标识 2. 在发起新请求前检查是否存在相同标识的未完成请求 3. 如果存在则先中断旧请求 ```javascript // 请求映射表 const pendingRequests = new Map(); function requestWithCancel(url, params) { // 如果已有相同请求,先取消 if (pendingRequests.has(url)) { pendingRequests.get(url).abort(); pendingRequests.delete(url); } const controller = new AbortController(); pendingRequests.set(url, controller); return axios.get(url, { params, signal: controller.signal }).finally(() => { pendingRequests.delete(url); }); } // 在Vue组件中使用 export default { methods: { search(query) { requestWithCancel('/api/search', { q: query }) .then(res => this.results = res.data); } } } ``` ### 四、注意事项 1. **错误处理**:取消请求会触发`catch`,需用`axios.isCancel()`区分 2. **内存泄漏**:确保在取消请求后释放对控制器的引用 3. **兼容性**:现代浏览器均支持`AbortController`,如需支持老旧浏览器可使用[polyfill](https://github.com/mo/abortcontroller-polyfill) > **最佳实践总结**: > - 简单场景直接在组件内使用`AbortController` > - 复杂应用建议通过拦截器统一管理 > - 高频触发场景(如搜索)需主动中断前序请求 --- §§相关问题§§ 1. 在Vue中如何实现全局的Axios请求拦截器? 2. 如何避免Vue组件卸载后仍执行Axios回调? 3. Axios中断请求与Vue的keep-alive组件如何协作? 4. 在Vuex中如何管理Axios请求的中断? [^1]: Axios在Vue.js [^2]: vue中断axios请求 [^3]: Vue.js与axios</think>### 在 Vue.js 中使用 Axios 中断 HTTP 请求 以下是几种在 Vue 中实现请求中断的实用方法,结合最佳实践和常见场景: #### 一、组件内中断请求(推荐 AbortController) ```vue <script> import axios from 'axios'; export default { data() { return { controller: null, // 存储控制器实例 data: null } }, methods: { async fetchData() { // 创建新控制器(先取消前一个请求) if (this.controller) this.controller.abort(); this.controller = new AbortController(); try { const res = await axios.get('/api/data', { signal: this.controller.signal }); this.data = res.data; } catch (err) { if (axios.isCancel(err)) { console.log('请求被取消', err.message); } else { // 处理其他错误 } } } }, beforeUnmount() { // 组件销毁时自动取消请求 if (this.controller) this.controller.abort(); } } </script> <template> <button @click="fetchData">获取数据</button> <button @click="controller?.abort('用户取消')">取消请求</button> </template> ``` #### 二、全局请求列表管理(防止重复请求) 在 `main.js` 中设置全局请求管理器: ```javascript // main.js import { createApp } from 'vue' import App from './App.vue' import axios from 'axios' const app = createApp(App) // 全局请求列表 app.config.globalProperties.$httpRequestList = new Map() // 请求拦截器 axios.interceptors.request.use(config => { const source = new AbortController() config.signal = source.signal // 存储取消方法 const url = config.url if (app.config.globalProperties.$httpRequestList.has(url)) { app.config.globalProperties.$httpRequestList.get(url).abort() } app.config.globalProperties.$httpRequestList.set(url, source) return config }) // 响应拦截器 axios.interceptors.response.use( response => { // 请求完成后移除 const url = response.config.url app.config.globalProperties.$httpRequestList.delete(url) return response }, error => { if (axios.isCancel(error)) { return Promise.reject({ type: 'CANCEL', message: error.message }) } return Promise.reject(error) } ) ``` #### 三、搜索框防抖 + 中断(经典场景) ```vue <script> export default { data() { return { controller: null, searchResults: [] } }, methods: { search: _.debounce(function(query) { // 使用 lodash 防抖 if (this.controller) this.controller.abort() this.controller = new AbortController() axios.get('/api/search', { params: { q: query }, signal: this.controller.signal }).then(res => { this.searchResults = res.data }) }, 300) // 300ms 防抖延迟 } } </script> <template> <input @input="e => search(e.target.value)" placeholder="搜索..."> </template> ``` #### 四、路由切换自动取消请求 在路由守卫中实现: ```javascript // router.js import { createRouter } from 'vue-router' const router = createRouter({ ... }) router.beforeEach((to, from, next) => { // 获取全局请求列表 const requestList = app.config.globalProperties.$httpRequestList // 取消所有进行中的请求 if (requestList.size > 0) { requestList.forEach(controller => controller.abort()) requestList.clear() } next() }) ``` ### 关键注意事项 1. **错误处理**:必须使用 `axios.isCancel()` 区分取消错误和其他错误 ```javascript .catch(err => { if (axios.isCancel(err)) { console.log('请求取消:', err.message) } else { // 处理真实错误 } }) ``` 2. **内存管理**: - 组件销毁时在 `beforeUnmount` 中取消请求 - 使用全局列表时确保请求完成后移除控制器 3. **Vue 2 兼容**: ```javascript // Vue 2 使用 beforeDestroy beforeDestroy() { if (this.controller) this.controller.abort() } ``` 4. **TypeScript 支持**: ```typescript declare module '@vue/runtime-core' { interface ComponentCustomProperties { $httpRequestList: Map<string, AbortController> } } ``` > **最佳实践建议**: > 1. 简单场景使用组件内 `AbortController` > 2. 中大型项目使用全局请求列表 + 拦截器方案 > 3. 高频操作(如搜索)必须结合防抖/节流 + 中断[^2] > 4. 路由切换时自动取消当前页所有请求提升性能[^1] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值