JavaScript提取API中的错误处理
#javascript #网络开发人员 #前端 #fetch

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。

捕获的快乐错误!