Skip to the content.

终止请求

需求

在项目开发过程中,会有取消已发送请求的要求。

比如


XMLHttpRequest


XMLHttpRequest 本身支持请求中断(abort)

const xhr = new XMLHttpRequest();
xhr.method = "GET";
xhr.url = "https://slowmo.glitch.me/5000";
xhr.open(method, url, true);
xhr.send();

// 中断请求
xhr.abort();

Fetch


中断一个 fetch 请求,主要使用 AbortController 实现

AbortControllerAbortSignal 这些 API 是由 DOM 标准规范 提供的,而不是由语言本身提供的。

// 创建 AbortController 的实例
const controller = new AbortController();
const signal = controller.signal;

// 监听 abort 事件,在 controller.abort() 执行后执行回调打印
signal.addEventListener("abort", () => {
  console.log(signal.aborted); // true
});

// 触发中断
controller.abort();

使用 AbortController 中断 fetch 请求

// common.js
const signalCache = {};
// 创建一个signal
export function newSignal(key) {
  // 用于中断请求,避免数据加载时间过长时,同一接口先请求却后返回数据带来的数据错位问题
  if ("AbortController" in window) {
    signalCache[key + "Controller"] = new AbortController();
  }
  return signalCache[key + "Controller"];
}

// 执行abort方法,停止指定key的AbortController
export function stopSignal(key) {
  if ("AbortController" in window) {
    signalCache[key + "Controller"] && signalCache[key + "Controller"].abort();
    delete signalCache[key + "Controller"];
  }
}
...

export default function request(url, options) {
...

  let newOptions = { ...options };
  // 配置signal
  if(newOptions.body && newOptions.body.signal) {
    const signal = newOptions.body.signal;
    delete newOptions.body.signal;
    newOptions = { ...newOptions, signal };
  }

  return fetch(url, newOptions)
  .then((res) => {})
  // 如果请求完成了,调用abort()不会发生错误
  // 如果请求没有完成,那么Fetch就会抛出一个DOMException异常,异常的name属性值为"AbortError",因此要用catch捕获异常
  .catch((err) => {
     if (err.name === 'AbortError') {
          console.log('Fetch aborted');
     } else {
         console.log('Another error');
     }
}
import { newSignal } from './common.js';
 dispatch({
   type: 'exampleModel/fetchMyList',
    payload: {
      ...params,
      signal: newSignal('myList').signal,
    },
  });
...
import { stopSignal } from "./common.js";
stopSignal("myList");

参见



Axios

// request.js

axios.post("/list", obj, {
  onUploadProgress: (progress) => {
    //处理进度
  },
  cancelToken: new axios.CancelToken(function excutor(c) {
    //把每一个请求cancel函数都集中起来,调用cancel函数可中断请求
    dispatch({
      type: "app/setCancelToken",
      payload: c,
    });
  }),
}).catch(err => {
    if (err && err.message === '终止请求') return;
};
// app.js
...

namespace: "app",
state: {
    cancelTokenList: [],//请求取消队列
},
reducers: {
    // 设置取消
    setCancelToken(state, payload) {
      let cancelTokenList = state.cancelTokenList;
      cancelTokenList.push(payload);
      return { ...state, cancelTokenList };
    },
    // 清空
    clearCencelToken(state) {
      return { ...state, cancelTokenList: [] };
    }
  },
...
// index.js
componentWillUnmount() {
    const { app: { cancelTokenList } ,dispatch} = this.props;
    cancelTokenList.map((d,i)=>{
        d('终止请求');
        console.log('终止请求',new Date().getTime());
    });
    dispatch({ type: 'app/clearCencelToken'});
}