如何在API服务器挂起的情况下处理Axios超时



在尝试使axios的timeout方法工作时遇到问题。

为了测试:我设置了一个故意坏的API端点:它接受一个请求,抛出一个错误(例如:throw new Error(“testing for timeout”)(,并且故意不做任何其他事情。

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

样本代码:

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

编辑(~2020(:

在进一步的研究中,axiostimeout似乎只适用于响应超时,而不是连接暂停。连接超时的建议解决方案是取消方法(例如signalcancelToken (deprecated)(:

测试并工作:

const source = CancelToken.source();
try {
let response = null;
setTimeout(() => {
if (response === null) {
source.cancel();
}
}, 2000);

response = await axios.post('/url',null,{cancelToken: source.token});
// success
} catch (error) {
// fail
}

使用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();

在服务器端,我等待了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);

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

test1 pressed
pre call
Mon, 28 Jun 2021 09:01:54 GMT
Mon, 28 Jun 2021 09:01:56 GMT
post call failed

EDIT我测试创建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();

如@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) {
//...
});

示例带有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) {
//...
});

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

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

请参阅解决方案的原始答案

最新更新