AbortController取消请求

618 阅读1分钟

AbortController是一个Web API,它提供了一个信号对象(AbortSignal),该对象可以用来取消与Fetch API相关的操作。

使用方法:

1. 创建AbortController实例

const controller = new AbortController();

2. 获取AbortSignal对象

const signal = controller.signal;

3.fetch请求或axios请求中取消请求

const controller = new AbortController();

fetch(url, { signal:controller.signal }).then(response => {
    // 处理响应数据
}).catch(error => {
    if (error.name === 'AbortError') {
        console.log('Fetch 请求已被取消');
    } else {
        // 处理其他错误
    }
});
controller.abort();
const controller = new AbortController();

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// 取消请求
controller.abort()

实战

使用 express 快速搭建一个服务

// npm init
// npm i express
let express = require("express");
const app = express();

// express@4.xx
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.all("", function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Content-Type");
  res.header("Access-Control-Allow-Methods", "*");
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

// 定义一个GET路由: 模拟网络请求不稳定场景
app.get("/getUser", (req, res) => {
  console.log("get---query", req.query);
  setTimeout(() => {
    res.send({
      code: 0, 
      msg: "get请求成功", 
      data: req.query,
    });
  }, 3000);
});

// 监听3000端口
app.listen(3000, () => {
  console.log("Server is running on port 3000");
});

封装axios请求 /utils/request.js

import axios from 'axios'

const instance = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  //   baseURL: '/',
  // 超时
  timeout: 100000
})
// 存储需要被取消的控制器 key:url value:AbortController实例
const abortControllerMap = new Map()
// request拦截器
instance.interceptors.request.use(
  (config) => {
    // 省略其他配置....
   
   // 对于需要被取消的请求进行处理
    if (config.enableAbort) {
      const abortController = abortControllerMap.get(config.url)
      abortController && abortController.abort()
      const controller = new AbortController()
      config.signal = controller.signal
      abortControllerMap.set(config.url, controller)
    }

    return config
  },
  (error) => {
    console.log(error)
    Promise.reject(error)
  }
)

instance.interceptors.response.use(
  (res) => {
    // 释放已发送完毕的请求
    abortControllerMap.delete(res.config.url)
    return res
  },
  (err) => {
    console.error('err', err)
  }
)
export default instance

新建业务api api/about.js

import request from '@/utils/request'

// 模拟一个需要被取消的请求
export const getUserApi = (data) => {
  return request.get('/api/getUser', {
    params: data,
    enableAbort: true
  })
}

实际业务页面去调用

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <input type="text" @input="onInput" v-model="keyWord" />
  </div>
</template>
<script setup>
import { ref } from 'vue'
import { getUserApi } from '@/api/about.js'

const keyWord = ref('')
const onInput = async () => {
  const res = await getUserApi({ keyWord: keyWord.value })
  console.log('res', res)
}
</script>