axios: Response timeout does not work as expected

The following code doesn’t work as expected (no timeout error is fired):

 client.get('/stop-writing-body-halfway', {
    timeout: 100,
 })

After a few minutes, a response is resolved despite Content-Length not having been reached and the server not explicitly closing the connection. Edit: never mind the connection is probably closed after 2 mins because of https://nodejs.org/api/http.html#http_server_timeout

My server never closes the connection and stops writing the body half way:

  const stopWritingBodyHalfway = (msg, res) => {
    res.setHeader('Content-Length', 500)
    const body = Buffer.alloc(250, 'a')
    res.write(body)
  }

Is the timeout only for the request, not for the response?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 17
  • Comments: 20 (2 by maintainers)

Most upvoted comments

In case it’s useful to anyone I’ve been patching the behaviour of timeout by using an interceptor. It uses a cancel token to cancel the request after timeout has elapsed.

const requestTimeoutInterceptor = config => {
  if (config.timeout === undefined || config.timeout === 0) {
    return config;
  }

  const source = axios.CancelToken.source();

  setTimeout(() => {
    source.cancel(`Cancelled request. Took longer than ${config.timeout}ms to get complete response.`);
  }, config.timeout);

  // If caller configures cancelToken, preserve cancelToken behaviour.
  if (config.cancelToken) {
    config.cancelToken.promise.then(cancel => {
      source.cancel(cancel.message);
    });
  }

  return { ...config, cancelToken: source.token };
};


axios.interceptors.request.use(requestTimeoutInterceptor);

@olalonde Yes, exactly. At the moment, the current timeout is cleared before the response body has been completely received:

https://github.com/mzabriskie/axios/blob/master/lib/adapters/http.js#L116

The timeout gets cleared before the body stream is processed.

Instead the timeout could be be cleared later (when the body has been completely received).

I’ve come to this solution.

const defaultConfig = {
  method: 'GET',
  params: null,
  data: null,
  timeout: 2000
};

const fetch = (url, method, config) => {
  const finalConfig = Object.assign({}, defaultConfig, config);
  return axios({
    url,
    method,
    params: finalConfig.params, // QUERY
    data: finalConfig.data, // REQUEST
    headers: finalConfig.headers,
    timeout: finalConfig.timeout,
  }).then(response => {
    if(response.headers['content-length'] > response.request._response.length){
      response.__incomplete = true;
    }

    return response;
  });
};
`

On a related note, I wrote https://github.com/blockai/broken-http-server to help test those sort of things in my code. Could be helpful in axios tests.

@Rewieer @all, Even I was facing this issue. I used to stop the server where I send API requests and then I used to make a request. It used to take minutes for displaying the error message.

Then I found a solution provided by someone in the issues. I do not remember the issue number or title. (Please attach the issue here if someone recognizes the title of the issue from the code I am providing)

This is what I did:

// Rough implementation. Untested.
// This is the code provided by some angel
export function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("timeout"));
    }, ms);
    promise.then(resolve, reject);
  });
}

// This is how I implemented it in my code
    return timeout(5000, axios.get(`${ROOT_URL}/customer/${id}`)).then((response) => {

        if(response.status === 200) {

          // Dispatch the success action
          dispatch(receiveAddr());

          return response;
        }
      }).catch(err => {

        // If there was a problem, we need to
        // dispatch the error condition
        if(err.data && (err.status >= 400 && err.status <= 600)) {
          dispatch(errAddr(err.data));
        } else {
          dispatch(errAddr('Please check your network connection and try again.'));
        }

        return err;
      });