Fetch API:请求完成后“await res.json()”会失败吗?

Posted

技术标签:

【中文标题】Fetch API:请求完成后“await res.json()”会失败吗?【英文标题】:Fetch API: Can 'await res.json()' fail after a completed request? 【发布时间】: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)

我想知道:

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

【问题讨论】:

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

以上是关于Fetch API:请求完成后“await res.json()”会失败吗?的主要内容,如果未能解决你的问题,请参考以下文章

fetch() 完成后如何调用函数

在 JavaScript 中拦截 fetch() API 请求和响应

嵌套的 fetch-es 完成后如何执行操作?

如何使用装饰器模式极大地增强fetch()

fetch网络请求 get 和 post

Fetch请求