如何在不取消API调用的情况下使用axios设置超时



作为背景,我有一个API调用,它的响应可能很长(在某些情况下超过一分钟,但大多数情况下为10-15秒(。我想做的是在客户端设置一个超时,同时后端继续处理调用。我使用axios来处理http请求,我知道有一个默认为0timeout密钥,这意味着没有超时,所以调用将继续,直到成功或失败。我试着将其设置为1,看看这将如何处理一毫秒的超时和呼叫被取消。。。这是有道理的。我现在的问题是,如何在不取消HTTP请求的情况下在客户端实现超时?一些代码可以让你了解我尝试过的内容。

import React from "react";
import axios from "axios"
function App() {
const fetchLongRequest = async () => {
try{
// All peachy over here if no timeout is implemented...
const myRequest = await axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json"
},
})
console.log("SUCCESS!", JSON.stringify(myRequest.data, null, 2))
}catch(error){
console.log("FAIL!", error.message)
}
}
return (
<button onClick={() => fetchLongRequest()}>Fetch</button>
);
}
export default App;

现在这是我介绍的超时

import React from "react";
import axios from "axios";
function App() {
const fetchLongRequest = async () => {
// timeout works as expected but I'd like to let the call go to the backend and do its thing. 
try {
const myRequest = await axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json",
},
timeout: 1,
});
console.log("SUCCESS!", JSON.stringify(myRequest.data, null, 2));
} catch (error) {
console.log("FAIL!", error.message);
}
};
return <button onClick={() => fetchLongRequest()}>Fetch</button>;
}
export default App;

我知道这个请求有点奇怪,因为它引发了很多问题,比如错误处理、如何知道这个调用何时完成等。我想得到一些关于如何完成这项任务的反馈。。。请:(

您只需要在请求之前设置一个超时

import React from "react";
import axios from "axios";
function App() {
const fetchLongRequest = async () => {

const waitTime = 5000;
setTimeout(() => console.log("Request taking a long time"), waitTime);
try {
const result = await axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json",
}
});
console.log("SUCCESS!", JSON.stringify(result.data, null, 2));
} catch(error) {
console.log("FAIL!", error.message);
}
};
return <button onClick = {() => fetchLongRequest()}>Fetch </button> ;
}
export default App;

下面的原始解决方案完全是小题大做

我认为这会做你想做的,使用Promise.rese

注意:就错误处理而言,这仍然不太正确

handleError函数纯粹是这样的,如果请求在超时前失败,则不会输出两次

import React from "react";
import axios from "axios";
function App() {
const fetchLongRequest = async () => {

const waitTime = 5000;
const handleError = error => {
// this makes sure that the FAIL output isn't repeated in the case when there's a failure before the timeout
if (!error.handled) {
if (error.timedout) {
console.log("TIMEDOUT", error.timedout);
} else {
console.log("FAIL!", error.message);
error.handled = true;
throw error;
}
}
};
const makeRequest = async () => {
try {
const result = await axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json",
}
});
console.log("SUCCESS!", JSON.stringify(result.data, null, 2));
} catch(error) {
return handleError(error);
}
};
const timer = new Promise((_, reject) => setTimeout(reject, waitTime, {timedout: "request taking a long time"}));
try {
await Promise.race([makeRequest(), timer]);
} catch(error) {
handleError(error);
}
};
return <button onClick = {() => fetchLongRequest()}>Fetch </button> ;
}
export default App;

顺便说一句,如果没有async/await,这个代码会干净得多——不过,公平地说,我使用async/await的能力不如单独使用Promises的能力——我从出现.catch:p 之前就使用了Promises

async/await实现

import React from "react";
import axios from "axios";
function App() {
const fetchLongRequest = () => {

const waitTime = 5000;
const handleError = error => {
// this makes sure that the FAIL output isn't repeated in the case when there's a failure before the timeout
if (!error.handled) {
if (error.timedout) {
console.log("TIMEDOUT", error.timedout);
} else {
console.log("FAIL!", error.message);
error.handled = true;
throw error;
}
}
};

const myRequest = axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json",
}
}).then(result => {
console.log("SUCCESS!", JSON.stringify(result.data, null, 2));
}).catch(handleError);

const timer = new Promise((_, reject) => setTimeout(reject, waitTime, {timedout: "request taking a long time"}));

return Promise.race([myRequest, timer]).catch(handleError);
};
return <button onClick = {() => fetchLongRequest()}>Fetch </button> ;
}
export default App;

当然";"清洁剂";只是我的意见

Axios API调用是promise-based,因此您可以在完成时简单地使用thencatch块来执行一些任务,而不使用await,然后它将在后台运行而不阻塞客户端。在这种情况下使用超时是不允许的,因为在慢速网络上可能需要一分钟才能完成,一旦超时完成,就会阻塞客户端。与其使用await来阻止您的请求,不如删除它,它只是异步运行,我认为这是您想要实现的。

const myRequest = axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json"
},
})

相关内容

最新更新