preface

There are numerous articles and materials on Axios cancellation requests. Most of them are separately introduced to cancel the unfinished request of the previous page or cancel the repeated request when switching routes, and most of them are introduced to the core content, lacking the description of a complete set of schemes.

This article describes a complete solution for switching routes to de-specify and de-duplicate requests, along with some other small dry goods processing

Request to intercept

About axios cancel request, the official document also has a simple description of the use method, I will not repeat the basic method here, directly write the scheme.

Ideas:

A variable is used to store requests that are currently in a pending state, indicated by an identifier. Intercept requests, judge whether there have been still in the pending before the API request of similar, namely the existence of the above variables, if present, cancel the processing, is not normal to send, there’s a request, such as delete the API request after identified in the above variables, it is a complete process of dealing with the cancel the repeat request.

For switched routes (pages), in order to cancel the requests that are still pending on the previous page, it is necessary to listen to the route switching, and judge the request identifiers stored in the above variables each time the switching, which are the requests to be cancelled, just cancel them. Not all pending requests are cancelled, because some requests in the system need not be cancelled due to route switching, such as some global requests. Of course, this can be extended to specify what needs to be cancelled for your actual project.

Regarding the request effect Settings, I am used to a separate file http.js, code comments written step by step is very clear, you read the natural very easy to understand.

// http.js

import axios from 'axios';

// Used to store the status of pending requests
let pendingRequest = [];

/** * @param config - Request configuration item */
const handleRequestIntercept = config= > {
    // The method name + the request path
    // If there are multiple requests for different baseurLs in a project
    ${config.method} ${config.baseURL}${config.url}
    const requestMark = `${config.method} ${config.url}`;
    PendingRequest = pendingRequest = pendingRequest = pendingRequest
    const markIndex = pendingRequest.findIndex(item= > {
        return item.name === requestMark;
    });
    // Exist, that is, repeat
    if (markIndex > - 1) {
        // Cancel the previous duplicate request
        pendingRequest[markIndex].cancel();
        // Delete the request identifier in pendingRequest
        pendingRequest.splice(markIndex, 1);
    }
    // (re) create a cancelToken for axios for this request
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    config.cancelToken = source.token;
    // Set up a custom configuration requestMark item, which is mainly used in response interception
    config.requestMark = requestMark;
    // Record the identity of this request
    pendingRequest.push({
        name: requestMark,
        cancel: source.cancel,
        routeChangeCancel: config.routeChangeCancel // There may be a routeChangeCancel item with a higher priority than the default
    });
    
    return config;
};

/** * Response interception processing * @param config - request configuration item */
const handleResponseIntercept = config= > {
    // Find the pendingRequest identifier based on the requestMark configuration set in request interception
    const markIndex = pendingRequest.findIndex(item= > {
        return item.name === config.requestMark;
    });
    // Delete the flag
    markIndex > - 1 && pendingRequest.splice(markIndex, 1);
}

/** * create an axios instance * @param {String} url - access the main url of the background */
const createAxiosInstance = (baseUrl) = > {
    let instance = axios.create({
        baseURL: baseUrl
    });
    // By default, the pending request is cancelled if the request is considered to be switched. False: the pending request is not cancelled
    instance.defaults.routeChangeCancel = true;
    
    // Request interception
    instance.interceptors.request.use(handleRequestIntercept, error => Promise.reject(error));
    
    // Response interception
    instance.interceptors.response.use(res= > {
        handleResponseIntercept(res.config);
        // More often you get res.data
        // Return res.data;
        return res;
    }, error => {
        let errorFormat = {};
        const response = error.response;
        // The request has been sent, but the status code of the server response is outside the 2xx range
        if (response) {
            handleResponseIntercept(response.config);
            // Set the format of the returned error object (according to your actual project requirements)
            errorFormat = {
                status: response.status,
                data: response.data
            };
        }
        // If the request is cancelled, mark it
        if (axios.isCancel(error)) {
            errorFormat.selfCancel = true;
        }
        // There is another case
        Error. Message is the error message when setting a request that raises an error
        // But I think this is usually a script error, our project prompt should not prompt the script error to the user, usually we customize some default error message, such as "created successfully!"
        // So there is no processing for this case.
        
        return Promise.reject(errorFormat);
    });
    
    // There are some other axios instance Settings you want
    // ...
    
    return instance;
}

// Other configurations
// ...

export {
    pendingRequest
}
Copy the code

The pending request is cancelled when the route is switched. The pending request is cancelled when the route is switched.

In the routing Settings file, use vue-router as an example

// router.js

import { pendingRequest } from 'http.js';

/ /... This is the other configuration

router.beforeEach((to, from, next) = > {
    // Cancel requests that have not finished on the previous page
    pendingRequest.forEach(item= > {
        item.routeChangeCancel && item.cancel();
    });
    / /... Other processing
});
Copy the code

Actual project application

Processing error

Above we decided how to do interception, how to deal with route switching, basically already dealt with.

A few more minor points, remember that we did a test for the response intercept to determine if it was an active cancel, and then set the selfCancel flag.

What’s the use of this? It is used to handle error messages when we make requests in the project. Such as

// I created an axios instance and tied it to Vue's HTTP
Vue.http.get('/api/test').then(res= > {
    // Successful request processing
}).catch(e= > {
    // If the request is unsolicited, the request is cancelled
    e.selfCancel || this.$message.error('Request failed! ');
})
Copy the code

This.$message.error here is mainly used to prompt the error message to the user. Since we cancel the request initiatively, we will go into the catch process, but this is not an error in the actual sense, so we should not tell the user that there is an error.

Therefore, this selfCancel mark is used to tell the developer that this is an error caused by our initiative to cancel the request, and the user should not be prompted to see it

Distinguish whether a page is requested

We used the request config.routeChangeCancel above to determine whether to cancel pending requests when switching routes.

The default routeChangeCancel is set to true when we create an axios instance. When we switch routes, we usually want to cancel the unfinished requests on the last page, so as to avoid the problems such as script errors reported if there are changes or methods or DOM objects related to the last page when the callback function processing is completed due to the switch of routes. Of course, this is also a performance optimization process to improve the user interaction experience, so this is necessary.

Some people might think, just switch the route and cancel all the pending requests. However, there may be some public requests on your system that are not and should not be affected by page switching, and such requests should not be cancelled when switching routes! A common example is that some information in the header of the system needs to be requested. Switching the header of the page does not change, right?

So we have been through the instance. The defaults. RouteChangeCancel = true set, then how to set the request to know which don’t need to cancel switch routing?

Vue.http.get('/api/test', {
    routeChangeCancel: false
})
Copy the code

This is overridden when the instance sends the request

In fact, if you don’t want to differentiate in this way, you can actually create two axios instances, one indicating that switching routes should be cancelled, and one that doesn’t need to be cancelled. But IN my opinion, this kind of request that does not need to cancel is less in a project, in a system, in fact, it is more flexible through the form of this configuration, and it is not a lot of trouble to deal with.

conclusion

So much for the cancellation scenario.

Please do not reprint without permission

It starts in front of K