如何处理 Axios 超时与挂起的 API 服务器?

and*_*rew 29 javascript reactjs axios

尝试使timeoutaxios 工作的方法时遇到问题。

\n

为了测试:我故意设置了一个错误的 API 端点:它接受请求,抛出错误(例如:)throw new Error(\xe2\x80\x9ctesting for timeout\xe2\x80\x9d)并且故意不执行任何其他操作。

\n

一旦我调用测试 API 端点,我的客户端应用程序 (reactJS) 就会挂起 - 我预计它会在 2 秒内超时(我设置的超时)。我可以验证该应用程序正在与服务器建立联系。只有当我终止测试 API 服务器时,我的客户端应用程序才会立即继续。

\n

示例代码:

\n
const axios = require(\'axios\')\n\nconst test1Press = async () => {\n  try\n  {\n    await axios.post(\'https://mynodeserver.com/api/debug/throw\', {timeout: 2000})\n    console.log("post call passed")\n  }\n  catch (err)\n  {\n    console.log("post call failed")\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

编辑(~2020):

\n

经过进一步研究,看起来 axiostimeout仅适用于响应超时,而不适用于连接超时。针对连接超时的建议解决方案是取消方法(例如signalcancelToken (deprecated)):

\n

对此进行了测试并工作:

\n
const source = CancelToken.source();\ntry {\n  let response = null;\n  setTimeout(() => {\n    if (response === null) {\n      source.cancel();\n    }\n  }, 2000);\n        \n  response = await axios.post(\'/url\',null,{cancelToken: source.token});\n  // success\n} catch (error) {\n  // fail\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Đăn*_*inh 27

使用await axios.post('/debug/throw', {timeout: 2000}),实际上您将有效负载发送 {timeout: 2000}到服务器,而不是将超时设置为 2 秒。请参阅此处的示例。

我用 axios 的另一种语法进行了测试,它有效

const test1Press = async () => {

    console.log("test1 pressed")

    // obviously not the actual url in this stackoverflow post
    axios.defaults.baseURL = 'http://localhost:9000'

    console.log("pre call")
    console.log(new Date().toUTCString());
    try {
        await axios({
            method: 'post',
            url: '/',
            timeout: 2000 // only wait for 2s
        })
        console.log(new Date().toUTCString());
        console.log("post call passed")
    }
    catch (err) {
        console.log(new Date().toUTCString());
        console.log("post call failed")
    }
}

test1Press();
Run Code Online (Sandbox Code Playgroud)

在服务器端,我等待5秒,客户端出现超时错误

const http = require('http');

const server = http.createServer(function (req, res) {
    setTimeout(function () {
        res.write('Hello World!');
        res.end();
    }, 5 * 1 * 1000); // after 5s
})
    .listen(9000);
Run Code Online (Sandbox Code Playgroud)

运行上面的代码 2 秒后出现超时错误

test1 pressed
pre call
Mon, 28 Jun 2021 09:01:54 GMT
Mon, 28 Jun 2021 09:01:56 GMT
post call failed
Run Code Online (Sandbox Code Playgroud)

编辑 我测试创建 axios 实例,这给了我相同的结果:

const test1Press = async () => {

    console.log("test1 pressed")

    // obviously not the actual url in this stackoverflow post
    const instance = axios.create({
        baseURL: 'http://localhost:9000',
        timeout: 2000,
    });

    console.log("pre call")
    console.log(new Date().toUTCString());
    try {
        await instance.post('/');
        console.log(new Date().toUTCString());
        console.log("post call passed")
    }
    catch (err) {
        console.log(new Date().toUTCString());
        console.log("post call failed")
    }
}

test1Press();
Run Code Online (Sandbox Code Playgroud)


Pot*_*mer 6

正如@arthankamal 答案中所示,timeout属性仅负责响应超时,但不负责连接超时。要解决连接超时问题,请使用axios 的取消方法。基于较新的signal属性添加以下示例(cancelToken已弃用)。


signal内置AbortSignal.timeout()示例[需要 Nodejs 17.3+]:

axios({
  method: 'get',
  url: '/foo/bar',
  timeout: 5000,
  signal: AbortSignal.timeout(5000) //Aborts request after 5 seconds
})
.then(function(response) {
  //...
});
Run Code Online (Sandbox Code Playgroud)

带有signal超时辅助函数的示例:

function newAbortSignal(timeoutMs) {
  const abortController = new AbortController();
  setTimeout(() => abortController.abort(), timeoutMs || 0);

  return abortController.signal;
}

axios({
  method: 'get',
  url: '/foo/bar',
  timeout: 5000,
  signal: newAbortSignal(5000) //Aborts request after 5 seconds
})
.then(function(response) {
  //...
});
Run Code Online (Sandbox Code Playgroud)


Ham*_*eed 0

假设您通过 axios 请求了 URL,并且服务器需要很长时间才能响应,在这种情况下 axios 超时将起作用。

但是您没有互联网连接,或者您请求的 IP 地址或域名不存在,在这种情况下 axios 超时将不起作用。

解决方法见原答案