【问题标题】:Fetch API: Can 'await res.json()' fail after a completed request?Fetch API:请求完成后“await res.json()”会失败吗?
【发布时间】:2020-04-30 21:31:07
【问题描述】:

只有在出现网络或服务器错误时,提取 API 请求才会失败。例如,如果我执行以下代码,假设它通过try 块没有错误,我将得到一个有效的填充res

try {
    const res = await fetch('/createurl', { 
        method: 'POST',
        body: 'testData',
        headers: {
            'Content-Type': 'application/json'
        }
    })

    if (res.ok) {
        alert('Resource created!')
    } else {
        alert('Error creating resource!')
    }

    flashResponseToUser(res)
} catch(e) {
    alert('A server or network error occurred during the request!')
}

我正在处理res 以使用flashResponseToUser(res) 函数向用户显示必要的errorsuccess 消息。由于res.json() 返回一个PromiseflashResponseToUser 必须是一个异步函数。

const flashResponseToUser = async(res) => {
    const jsonRes = await res.json() // Get data from response
    console.log(jsonRes)
}

我想知道:

  1. 为什么res.json()返回Promise,因为此时客户端已经收到响应?
  2. 在什么情况下res.json()返回的Promise会失败?
  3. 由于我使用的是res.json()flashResponseToUser(res) 中的代码是否也需要包装在 try-catch 块中?

【问题讨论】:

  • developer.mozilla.org/en-US/docs/Web/API/Body 这将能够帮助您解决这些问题。
  • @Siege21x 我确实读过,但它仍然没有解释为什么 res.json() 返回一个 Promise 而不是直接返回数据。也没有告诉我们 res.json() 在什么情况下失败。
  • answer 第一个问题。 answer 第二个问题。

标签: javascript promise fetch-api


【解决方案1】:

为什么 res.json() 会返回一个 Promise,因为此时客户端已经收到了响应?

fetch 返回一个响应对象。这表明响应的 headers 已收到,但并不一定意味着整个响应已收到 - 例如,当您加载一个巨大的页面时。这不是完全相同的东西,但是您会收到标头并且浏览器将开始加载响应,即使还有更多要下载的内容。 Response 对象提供了标头和一种方法来处理仍然传入的数据。

res.json()返回的Promise在什么情况下会失败?

如果响应不是正确的 JSON 格式,它可能会失败。例如,如果响应的纯文本是 Internal Server Error,它不是 JSON。这是一个例子:

(async () => {
  const response = await fetch('data:,Internal%20Server%20Error');
  console.log('got response');
  try {
    await response.json();
  } catch(e) {
    console.log('error:', e.message);
  }
})();

由于我使用的是 res.json(),flashResponseToUser(res) 中的代码是否也需要包装在 try-catch 块中?

如果您想绝对安全,可以。但是,在大多数情况下,最简单的方法是在一个地方捕获,您可以在其中处理错误。您可以在消费者中只处理一次错误,而不是在流程的每个步骤中处理可能的错误,例如:

const getInfo = async () => {
  const res = await fetch('/createurl', { 
    method: 'POST',
    body: 'testData',
    headers: {
      'Content-Type': 'application/json'
    }
  })

  if (!res.ok) {
    throw new Error(res.status);
  }
  return res.json();
};
getInfo()
  .then(flashResponseToUser)
  .catch(() => {
    alert('A server or network error occurred during the request!')
  })

(假设flashResponseToUser 永远不会抛出,如果提供了预期的对象。如果flashResponseToUser 无论如何都可能抛出,您可以分离出.catches 以区分网络错误和其他运行时错误)

【讨论】:

  • 谢谢!很好的解释。我会尽快将此标记为答案!
  • JSON 格式错误发生的频率比人们想象的要多。有时你的框架会返回一个错误页面,它是 HTML 而不是 json。有时您的反向代理(nginx 或 apache 前端)会返回一个错误页面,该页面是 HTML 而不是 json。有时您的办公室或 ISP 缓存服务器会返回一个错误页面,该页面是 HTML 而不是 json。您不一定能控制所有条件
  • 哦,别忘了公共Wifi有时会劫持你的请求并返回一个HTML而不是json的登录页面
猜你喜欢
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
  • 1970-01-01
相关资源
最近更新 更多