Required: how to interrupt a sent request?

Interviewer: the request has been sent. How to cancel the request?

Interviewer: (I immediately had a doubt in my mind: can I cancel the request that has been sent out?) This... This... I really don't know.

After the interview, find Du Niang immediately

Recommended reading: axios Analytic cancelToken Cancellation request principle[2]

AbortController

The AbortController[3] interface represents a controller object that can terminate one or more Web requests as needed.

  • AbortController(): the AbortController() constructor creates a new instance of the AbortController object

  • Signal: the signal property returns an AbortSignal object instance, which can be used to with/about a web request

  • abort(): terminate an unfinished web request. It can terminate the fetch request, any consumer and stream responding to the Body

Fetch interrupt request

Fetch is an interface provided by the Web for obtaining resources. If you want to terminate a fetch request, you can use the AbortController interface provided by the Web.

First, we use the AbortController() constructor to create a controller, and then use abortcontroller The signal property gets a reference to its associated AbortSignal object. When a fetch request is initialized, we pass AbortSignal as an option to the request object (as follows: {signal}). This associates the signal and controller with the acquisition request, and then allows us to call abortcontroller Abort() aborts the request.

const controller = new AbortController();
let signal = controller.signal;
 console.log('signal Initial state of: ', signal);

const downloadBtn = document.querySelector('.download');
const abortBtn = document.querySelector('.abort');

downloadBtn.addEventListener('click', fetchVideo);

abortBtn.addEventListener('click', function() {
  controller.abort();
 console.log('signal Abort status of: ', signal);
});

function fetchVideo() {
  //...
  fetch(url, {signal}).then(function(response) {
    //...
  }).catch(function(e) {
    reports.textContent = 'Download error: ' + e.message;
  })
}

When we abort the request, the network request becomes as follows:

Let's look at the status before and after AbortSignal abort:

You can see that the aborted property of the AbortSignal object changes from false at the beginning to true after abort.

Online operation example[4] (Code from MDN[5])

Abortcontroller has compatibility problems as follows:

axios interrupt request

axions interrupt requests can be made in two ways:

Mode 1

Use canceltoken The cause factory method creates a cancel token with the following code:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('https://mdn.github.io/dom-examples/abort-api/sintel.mp4', {
  cancelToken: source.token
}).catch(function (thrown) {
  // Determine whether the request has been aborted
  if (axios.isCancel(thrown)) {
    // The parameter throw is custom information
    console.log('Request canceled', thrown.message);
  } else {
    // Processing error
  }
});

// Cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

The aborted network request becomes as follows:

Let's look at the souce state at the beginning and after the abort:

It can be seen that the source state at the beginning and after the abort has not changed. So how do we judge the abort status of the request? axios provides us with an isCancel() method to determine the abort status of the request. The parameter of isCancel() method is the customized information when we abort the request.

Mode II

Create a cancel token by passing an executor function to the constructor of CancelToken:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // The executor function takes a cancel function as an argument
    cancel = c;
  })
});

// Cancel request
cancel('Operation canceled by the user.');

The browser operation results and methods are consistent one by one, which will not be repeated here.

Online operation example[6] (Code from MDN[7])

UMI request interrupt request

UMI request is based on fetch encapsulation and has the characteristics of both fetch and axios. The abort request is the same as fetch and axios. It will not be repeated. For details, see the official document abort request [8]

It should be noted that there is a problem with AbortController in the lower version browser polyfill, and UMI request does not provide AbortController to abort the request in some versions.

Using CancelToken to abort a request in a umi project

The default request Library in the umi project is umi request, so we can use the method provided by umi request to abort the request. In addition, dva can be used together in umi projects. Therefore, the following is a brief introduction to the process of using CancelToken to abort requests in dva.

1. Write the request function and cancel request function in the file under the services directory

import request from '@/utils/request';
const CancelToken = request.CancelToken;
let cancel: any;

// Upload contract documents to OSS
export async function uploadContractFileToOSS(postBody: Blob): Promise<any> {
  return request(`/fms/ossUpload/financial_sys/contractFile`, {
    method: "POST",
    data: postBody,
    requestType: 'form',
    // Pass an executor function to the constructor of CancelToken to create a cancel token
    cancelToken: new CancelToken((c) => {
      cancel = c
    })
  })
}

// Cancel contract file upload
export async function cancelUploadFile() {
  return cancel && cancel()
}

2. Write Effect in models:

*uploadContractFileToOSS({ payload }: AnyAction, { call, put }: EffectsCommandMap): any {
  const response = yield call(uploadContractFileToOSS, payload);
  yield put({
    type: 'save',
    payload: {
      uploadOSSResult: response?.data,
    }
  })
  return response?.data
},

*cancelUploadFile(_: AnyAction, { call }: EffectsCommandMap): any {
  const response = yield call(cancelUploadFile)
  return response

},

3. Trigger the corresponding action through the dispatch function on the page:

// Initiate request
dispatch({
  type: 'contract/fetchContractFiles',
  payload: {
    contractId: `${id}`,
  }
})

// Cancel request
dispatch({
  type: "contract/cancelUploadFile"
})

4. In utils / request JS to uniformly handle the interception of abort requests:

const errorHandler = (error: { response: Response }): Response => {
  const { response } = error;
  notification.destroy()

  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status, url } = response;

    notification.error({
      message: `Request error ${status}: ${url}`,
      description: errorText,
    });
  } else if (error?.['type'] === 'TypeError') {
    notification.error({
      description: 'An exception has occurred in your network. You can't connect to the server',
      message: 'Network exception',
    });
  } else if (error?.['request']?.['options']?.['cancelToken']) {
    notification.warn({
      description: 'The current request has been cancelled',
      message: 'Cancel request',
    });
  } else if (!response) {
    notification.error({
      description: 'An exception has occurred in your network. You can't connect to the server',
      message: 'Network exception',
    });
  } else {
    notification.error({
      description: 'Please contact the website developer for processing',
      message: 'unknown error',
    });
  }
  return response;
};

Author: Zisheng
https://juejin.cn/post/7033906910583586829
Please indicate the source for reprint

Keywords: axios http

Added by ArcAiN6 on Fri, 07 Jan 2022 10:18:23 +0200