Fetch怎么了?
在JavaScript中使用Fetch时,经常被忽略的内容是从响应中处理正确的错误。那个捕获块可能没有做您认为正在做的事情!
在以下代码片段中,我们将使用React应用程序中介绍一个示例,该示例使用GET方法获取供应商名称列表,然后将其设置为状态。错误处理适用于使用JavaScript中的获取的所有情况,而不仅仅是在React中。
让我们从下面的示例开始。
/* Initializing vendors to an empty array */
const [vendors, setVendors] = React.useState([]);
/* useEffect runs on mount to fetch data */
React.useEffect(() => {
/* Setting up the fetch call */
const fetchVendors = async () => {
const response = await fetch('http://localhost:9000/vendors');
const responseJSON = await response.json();
return responseJSON;
};
/**
* Calling fetchVendors. The intent is to set the response (vendor names)
* in React state using setVendors if the fetch is successful. If an error
* occurs, we do not want to set the state and instead want to log the error.
**/
fetchVendors()
.then((response) => setVendors(response))
.catch((error) => console.error('Logging Error', error));
}, []);
乍一看,如果从获取呼叫中收到的响应没有给出200作为状态代码,它将落入捕获块并记录错误。虽然这是不正确的,而不是获取的工作方式。
提取API返回了解决或拒绝的承诺。如果它解决了,它将进入“然后”,如果拒绝,它将进入“捕获”。当收到其他200以外的状态代码时,这并不意味着Fetch的响应不良。一个例子是,如果数据库未能连接。可以将后端配置为发送带有错误名称和错误消息的500状态代码。在我们的前端没有其他配置的情况下,它不知道应该进入捕获块。它只是假设我们成功地收到了后端的回应,解决诺言。 MDN Web Docs还指出,当发生网络错误而不是HTTP错误时,Fetch API仅将拒绝。这意味着获取的用户负责设置正确的错误处理。那么我们该怎么做?
检查响应的OK布尔值
如果我们记录了初始示例的以下响应:
const response = await fetch('http://localhost:9000/vendors');
这就是解决的响应的外观。这将根据几个因素,例如状态代码,本地测试等不同。
{
body: ReadableStream,
bodyUsed: true,
headers: Headers {},
ok: true,
redirected: false,
status: 200,
statusText: "OK",
type: "cors",
url: "http://localhost:9000/vendors"
}
进行接听电话时,接收到的响应将包含一个名为 ok 的键。这将是一个布尔值。除200个地位以外的任何其他事物都将把 ok 的价值设置为 false 。知道这一点,我们现在可以在获取电话中添加一张支票。
React.useEffect(() => {
const fetchVendors = async () => {
const response = await fetch('http://localhost:9000/vendors');
const responseJSON = await response.json();
/** This will throw an error if the response status is anything other than 200 */
if (!response.ok) {
throw new Error('Something is broken!');
}
return responseJSON;
};
fetchVendors()
.then((response) => setVendors(response))
.catch((error) => console.error('Logging Error', error));
}, []);
,如果我们收到200个响应以外的其他内容,并且它记录了“某物破裂!”。
检查响应的内容类型
如果我们收到的回复不是JSON类型怎么办?在运行以下代码时,我们可能会在检查 OK 之前会收到错误。
const responseJSON = await response.json();
响应还包含标题。通过标题,可以在以任何特定方式处理之前验证收到的内容类型。
React.useEffect(() => {
const fetchVendors = async () => {
let error;
const response = await fetch('http://localhost:9000/vendors');
/** Checking the response headers for the content type */
const isContentTypeJson = response.headers.get('content-type')?.includes('application/json');
/** If content is not JSON, will not be processed as a JSON and sets the error variable */
const responseData = isContentTypeJson
? await response.json()
: error = 'Not a JSON!';
if (!response.ok) {
throw new Error('Something is broken!');
}
// throw an error if error variable contains a value
if (error) {
throw new Error(error);
}
return responseData;
};
fetchVendors()
.then((response) => setVendors(response))
.catch((error) => console.error('Logging Error', error));
}, []);
promise.resolve()和Promise.Repject()
我们还可以使用 Promise.resolve()和 promise.reject.reject()来控制获取的流动,而不是直接抛出错误。假装我们将前端连接到后端,后端正在发送带有状态代码,错误名称和错误消息的JSON对象。假设我们要保留这些数据以登录我们的前端,则可以使用Promise..reject()将此数据作为捕获块的错误数据发送。
示例响应JSON从后端收到。这将是响应后的响应。
{
name: 'Database',
message: 'Failed to connect to database',
status: 500,
}
下面的示例允许使用后端的响应遵循一致的格式,可以进行更强大的错误处理和记录。
React.useEffect(() => {
const fetchVendors = async () => {
const response = await fetch('http://localhost:9000/vendors');
const isContentTypeJson = response.headers.get('content-type')?.includes('application/json');
/** Handle error object from backend */
const responseData = isContentTypeJson
? await response.json()
: { status: response.status, statusText: response.statusText };
if (!response.ok) {
/** since a 500 was received from backend, the flow would enter here and we can manually reject the Promise. This will move into the "catch" */
return Promise.reject(responseData);
}
/** If a 200 was received, the promise would resolve and flow moves to "then" */
return Promise.resolve(responseData);
};
fetchVendors()
.then((response) => setVendors(response))
/** error in the below case would contain { name: 'Database', message: 'Failed to connect to database', status: 500 } */
.catch((error) => console.error('Logging Error', error));
}, []);
包起来
可以处理通过fetch API处理错误的多种方法。这篇文章中给出的示例只有几个,并且会根据您的应用程序中的需求而更改。在这里要记住的重要作品是,假设Fetch会根据HTTP状态代码进入捕获块是不安全的! MDN Web文档指出,这只会在网络错误中发生,例如无效的URL。
捕获的快乐错误!