Извлечь API: Может ли 'await res. json ()' завершиться ошибкой после выполнения запроса? - PullRequest
7 голосов
/ 14 января 2020

Запрос 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 для показать пользователям необходимое сообщение error или success, используя функцию flashResponseToUser(res). Поскольку res.json() возвращает Promise, flashResponseToUser должна быть асин c функцией.

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

Я хочу знать:

  1. Почему res.json() вернуть Promise, так как в этот момент клиент уже получил ответ?
  2. При каких условиях Promise, возвращаемый res.json(), потерпит неудачу?
  3. Есть ли код в flashResponseToUser(res) также необходимо заключить в блок try-catch, так как я использую res.json()?

1 Ответ

8 голосов
/ 14 января 2020

Почему res. json () возвращает Promise, поскольку в этот момент клиент уже получил ответ?

fetch возвращает объект Response. Это указывает на то, что заголовки ответа были получены, но не обязательно означает, что весь ответ был получен - представьте, например, когда вы загружаете огромную страницу. Это не точно то же самое, но вы получите заголовки, и браузер начнет загружать ответ, даже если есть еще что-то для загрузки. Объект Response предоставляет заголовки и способ обработки все еще поступающих данных.

При каких условиях произойдет сбой Promise, возвращаемого res. json ()?

Может произойти сбой, если ответ был не в правильном формате 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);
  }
})();

Нужно ли заключать код в flashResponseToUser (res) в блок try-catch, так как я использую res. json ()?

Если вы хотите быть в полной безопасности, да. Но в большинстве случаев проще всего поймать одно место , где вы можете обработать ошибку. Вместо того, чтобы обрабатывать возможные ошибки на каждом этапе процесса, вы можете обработать ошибку только один раз в потребителе, например:

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 может все равно выдать, вы можете отделить .catch es, чтобы отличить guish сетевых ошибок от других ошибок времени выполнения)

...