SoFunction
Updated on 2025-04-04

Axios' interceptors execution problem is solved by solving multiple executions

question

In progressaxiosWhen encapsulating, I encountered a problem, that is, every time axios initiates a request, it will perform two response interceptions. I am very puzzled and can't figure it out for a while.

The code is as follows:

class Http {
    constructor(config) {
         = axios;
         = undefined;
        // Public header        let defaultHeaders = {
            'Content-Type': 'application/json;charset=UTF-8',
            'Accept': 'application/json', // Specify through header, the retrieved data type is JSON 'application/json, text/plain, */*',            'x-end-point': '.10.'
        }
        if(config?.headers){
            for (let i in ) {
                defaultHeaders[i] = [i];
            }
        }
        axios({
            // `baseURL` will be automatically added before `url` unless `url` is an absolute URL.            // It can facilitate the passing of relative URLs to the axios instance method by setting a `baseURL`            baseURL: config?.baseURL,
            // `url` is the server URL used for request            url: config?.url,
            // `method` is the method used when creating a request            method: config?.method || 'get',
            // `headers` is a custom request header to be sent soon            headers: {...defaultHeaders},
            // `params` is the URL parameter to be sent with the request            // Must be a plain object or URLSearchParams object            params: config?.method === 'get' ? config?.params || {} : {},
            // `paramsSerializer` is a function responsible for `params` serialization            // (. /package/qs, //)
            paramsSerializer: function(params) {
                return (params, {arrayFormat: 'brackets'})
            },
            // `data` is data sent as the requesting body            // Applicable only to these request methods 'PUT', 'POST', and 'PATCH'            // When `transformRequest` is not set, it must be one of the following types:            // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
            // - Browser exclusive: FormData, File, Blob            // - Node exclusive: Stream            data: config?.method === 'post' ? config?.params || {} : {},
            // `timeout` specifies the number of milliseconds for the request timeout (0 means no timeout)            // If the request charge exceeds the timeout, the request will be interrupted            timeout: 0,
            // `withCredentials` indicates whether credentials are required when requesting across domains            withCredentials: false, // If default is true, cross-domain, cross-domain carrying cookies are generated            // `responseType` represents the data type of the server response, which can be 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'            responseType: 'json', // default
        });
        // Add a request interceptor        ( (config) =>  {
            // What to do before sending a request            return config;
        }, function (error) {
            // What to do about the request error            return (error);
        });
        // Add a response interceptor        ((res) => {
            const { status, data } = res;
            // Handle error status prompts            let message = ''
            if (status < 200 || status >= 300) {
                // Handle http errors and throw them into business code                message = (status)
                if (typeof  === 'string') {
                     = {code:status, message }
                } else {
                     = status
                     = message
                }
            }
        return ;
        }, function (error) {
            // Do something to respond to errors            return (error);
        });
    }
    get(url,params={}){
        // Create a request for the user with a given ID        return new Promise((resolve, reject) => {
            (url,{
                params
            }).then(response => {
                // 2. If successful, call resolve(value)                resolve(response);
            })
                .catch(error => {
                    // 3. If it fails, do not call reject(reason), but prompt for exception information                    reject(error)
                    // ('The request error occurred: ' + ).then(r => {});                }).finally(() => {
            })
        });
    }
    post(url,params={}){
        return new Promise((resolve, reject) => {
            (url, params).then(response => {
                // 2. If successful, call resolve(value)                resolve(response);
            })
                .catch(error => {
                    // 3. If it fails, do not call reject(reason), but prompt for exception information                    reject(error)
                    // ('The request error occurred: ' + ).then(r => {});                }).finally(() => {
            })
        });
    }
    showResState (state) {
        let message = '';
        // Here are only some common examples, and configure them according to your needs        switch (state) {
            case 400:
                message = 'Request error(400)'
                break
            case 401:
                message = 'Unauthorized,Please log in again(401)'
                break
            case 403:
                message = 'access denied(403)'
                break
            case 404:
                message = 'Request error(404)'
                break
            case 500:
                message = 'Server Error(500)'
                break
            case 501:
                message = 'Service not implemented(501)'
                break
            case 502:
                message = 'Network error(502)'
                break
            case 503:
                message = 'Service not available(503)'
                break
            default:
                message = `There was an error in connection(${state})!`
        }
        return `${message},Please check the network or contact the website administrator!`
    }
    // The required configuration items will be passed in when the plug-in is initialized    autoAddToken (config) {
        // Modify the config configuration item during the request phase to add token to it. The specific attribute name can be customized.         ??= {}
         =  || null
        return config
    }
}
export default Http;

Friends who have encountered this type of problem may see the problem at a glance, and friends who have never encountered this problem may suffer a little more.

reason

If you use use, just like the use in it, you will constantly add interceptors to the axios object. Since I put the interceptor in the function, as long as the function is executed, the interceptor function will be added to the axios object again.

So, the recommended way is to put the interceptor outside the function, but my needs determine that I must put it inside the function, so how to solve it?

solve

Add the unique variable identifier in the file let interceptor = null to make judgments. As long as the interceptor exists, it will not continue to be added. Some codes are as follows:

if (!) {
// Add a response interceptor = ((res) => {
        const { status, data } = res;
        // Handle error status prompts        let message = ''
        if (status < 200 || status >= 300) {
            // Handle http errors and throw them into business code            message = (status)
            if (typeof  === 'string') {
                 = {code:status, message }
            } else {
                 = status
                 = message
            }
        }
    return ;
    }, function (error) {
        // Do something to respond to errors        return (error);
    });
  }

What's wrong. The interceptor must be extracted outside the class, and the problem must be solved.

Only some of the main codes are posted here:

import axios from "axios";
/* Place the interceptor outside the encapsulation class */
// Add a request interceptor( (config) =>  {
    // What to do before sending a request? Add token and other authentication functions    //...
    return config;
}, function (error) {
    // What to do about the request error    return (error);
});
// Add a response interceptor((res) => {
    const { status } = res;
    // What to do before sending the result? Handle the error status prompt    //...
    return ;
}, function (error) {
    // Do something to respond to errors    return (error);
});
class Http {
    constructor(config) {
         = axios;
        // The configuration still needs to be processed here, the code is omitted         = config;
    }
    // Get request    get(url,params={},headers={}){
        // ...
    }
    // POST request    post(url,params={},headers={}){
        // ...
    }
}
export default Http;
// If there is no special needs, just use this one object. The public header can be configured here. If multiple instances are needed, multiple instances can be created in this way for export.export const Axios = new Http({
    headers: {
        'x-http-token': 'xxx'
    }
});

The specific method is not described here, but only a description of the problem is made. In the future, we will write a separate article and then explain it in detail.

The above is the detailed content of solving the problem of multiple executions of axios interceptors. For more information about multiple executions of axios interceptors, please pay attention to my other related articles!