javascript - 如何在不取消 API 调用的情况下使用 axios 设置超时?
问题描述
一点背景知识,我有这个 API 调用,它的响应可能很长(在某些情况下谈论超过一分钟,但大部分时间为 10-15 秒)。我想做的是在后端继续处理呼叫时在客户端设置超时。我正在使用 axios 来处理 http 请求,并且我知道有一个timeout
默认键0
意味着没有超时,因此调用将继续,直到成功或失败。我试图将其设置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.race
注意:就错误处理而言,这仍然不太正确
该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 那样流利——我在使用 Promises 之前就已经使用了.catch
:p
非
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;
当然“更清洁”只是我的意见
推荐阅读
- java - 当元素包含 HTML 标记时,Jackson 反序列化 XML
- r - 来自 approx() 的结果控制顺序
- php - LARAVEL 6.x = 试图获取非对象的属性“id”
- node.js - 从nodejs webhook发送响应表单对话框流的正确方法是什么?
- django - Django Rest - 未创建具有 SlugRelatedField 数据的 ManyToManyField
- javascript - 递归数组修改
- rxjs6 - rxjs 可观察流:如何对每个第 n 个事件执行副作用?
- javascript - 将数据从 JS 下载到 JS html 文件中
- amazon-web-services - 如何从 Fargate 任务中正确公开 API?
- python - xlrd - 将 Excel 时间转换为 mysql 日期格式?