作为背景,我有一个API调用,它的响应可能很长(在某些情况下超过一分钟,但大多数情况下为10-15秒(。我想做的是在客户端设置一个超时,同时后端继续处理调用。我使用axios来处理http请求,我知道有一个默认为0
的timeout
密钥,这意味着没有超时,所以调用将继续,直到成功或失败。我试着将其设置为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
,因此您可以在完成时简单地使用then
和catch
块来执行一些任务,而不使用await
,然后它将在后台运行而不阻塞客户端。在这种情况下使用超时是不允许的,因为在慢速网络上可能需要一分钟才能完成,一旦超时完成,就会阻塞客户端。与其使用await
来阻止您的请求,不如删除它,它只是异步运行,我认为这是您想要实现的。
const myRequest = axios({
url: "https://jsonplaceholder.typicode.com/todos/1",
headers: {
accept: "application/json",
"Content-Type": "application/json"
},
})