Since using Vue2, we have used axios plug-in to call API, if the server or network is unstable and switched, how do you deal with it? Let me share with you my experience.

The specific reason

Recently, the company is working ona project. The server data interface uses THE API output from Php. Sometimes, it fails in the invocation process and shows Provisional Headers are shown in Google Browser.

According to the search engine to come out of the solution, can not solve my problem.


Recently in the research of AOP this concept of development programming, the axios development specification mentioned in the column Interceptors should be this mechanism, reduce the code coupling degree, improve the program reusability, and improve the efficiency of development.


Solution one with pits

In my limited experience, the only thing I can do is make a new request after the AXIos request times out. By studying the instructions for Axios, give it a timeout = 6000

axios.defaults.timeout =  6000;
Copy the code

Then add a column interceptor.

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
});

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
});
Copy the code

The purpose of this column interceptor is if after the request has timed out, the column interceptor can capture the information and then proceed to the next step, that is, I want to request again.

Here is the relevant page data request.

this.$axios.get(url, {params: {load:'noload'}}).then(function (response) {
	//dosomething();
}).catch(error= > {
	// Catch error messages here after timeout.
	if (error.response) {
		console.log('error.response')
		console.log(error.response);
	} else if (error.request) {
		console.log(error.request)
		console.log('error.request')
		if(error.request.readyState == 4 && error.request.status == 0) {// I hereby renew my request}}else {
		console.log('Error', error.message);
	}
	console.log(error.config);
});
Copy the code


After the timeout, Uncaught (in Promise) Error: timeout of XXX MS exceeded is displayed.

In catch, it returns an error. Request error, so the retry function is applied here. The retry function can be implemented after testing.

Look at the top, I have dozens of.vue files for this project, and I would go crazy if I had to set up a timeout re-request function for every page.

There’s a serious bug and the mechanism, is the requested link failure or other causes not normal visit, the mechanism of failure, it will not wait for me to set 6 seconds, and has been in the brush, one second request dozens of times, it is easy to bring down the server, please see below, the function of the twinkling of an eye, it made 146 requests.

Solution two with pits

Studied axios source code, after a timeout, the interceptor there axios. Interceptors. Response captured error messages, and the error. Code = “ECONNABORTED”, the specific links

https://github.com/axios/axios/blob/26b06391f831ef98606ec0ed406d2be1742e9850/lib/adapters/xhr.js#L95-L101

    // Handle timeout
    request.ontimeout = function handleTimeout() {
      reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED',
        request));

      // Clean up request
      request = null;
    };
Copy the code

So, my solution to global timeout recapture goes like this.

axios.interceptors.response.use(function(response){... },function(error){
	var originalRequest = error.config;
	if(error.code == 'ECONNABORTED' && error.message.indexOf('timeout')! =- 1 && !originalRequest._retry){
			originalRequest._retry = true
			returnaxios.request(originalRequest); }});Copy the code

This method can also make a new request, but there are two problems. One is that it only makes a new request once, and if it times out again, it stops making the request. The second problem is that I do a lot of things after each page that has a data request, such as this.$axios.get(URL).then.

Perfect solution

In the way of AOP programming, WHAT I need is a global function of timeout re-request.I need to work on axios.interceptors, find some solutions from others in axios issue on Github, and finally find a perfect solution, which is the following one.

https://github.com/axios/axios/issues/164#issuecomment-327837467

// Set the global number of requests in main.js, and the interval between requests
axios.defaults.retry = 4;
axios.defaults.retryDelay = 1000;

axios.interceptors.response.use(undefined.function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(! config || ! config.retry)return Promise.reject(err);
    
    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;
    
    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }
    
    // Increase the retry count
    config.__retryCount += 1;
    
    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });
    
    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});
Copy the code

The dozens of other.vue pages have this.$axios get and post methods that don’t need to be modified at all.

In the process, thank jooger gives a lot of technical support, this is his personal information, https://github.com/jo0ger, thank you.

Here’s an experiment I did. The axios. Defaults. RetryDelay = 500, request to www.facebook.com

If you have better suggestions, please let me know, thanks.

Making the source code