Javascript fetch body response

How to get response body when using fetch() in JavaScript

FetchAPI is designed to be easy to use and supports many different data formats including JSON, XML, and binary data. It provides a simple promised-based syntax for making HTTP requests and can be used in both the browser and Node.js environments.

When you use the fetch() method to make a request to a server, you will get back a promise that resolves to a Response object. The Response object represents the entire HTTP response, including the status, headers, and body. However, the body is not directly accessible as a string or an object, but rather as a stream of data that can only be read once.

To handle the response body, you need to use one of the methods of the Response object that returns another promise that resolves to the parsed data. These methods are:

  • .json() : Returns a Promise that resolves with the parsed JSON.
  • .text() : Returns a promise that resolves with a String.
  • .blob() : Returns a promise that resolves with a Blob, which represents a file-like object of immutable, raw data.
  • .arrayBuffer() : Returns a promise that resolves with an ArrayBuffer, which represents a generic, fixed-length binary data buffer.
  • .formData() : Returns a promise that resolves with a FormData, which is a key-value pair data structure used to submit form data.

Using .json()

Despite the method being named .json() , the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object. This object could be anything that can be represented by JSON — an object, an array, a string, a number, etc.

Читайте также:  If statement with string in python

Use this method when you want to get the response body as a JavaScript object parsed from JSON text. This is useful for working with data that follows the JSON format, such as most APIs. For example, you can use this method to get the user information from a GitHub API or the weather data from a weather API.

Here’s an example of making a request to the Reddit API and display the titles of the top posts on the front page using the .json() method:

async function getRedditPosts()  try  const response = await fetch('https://www.reddit.com/r/all/top.json?limit=10'); const data = await response.json(); const posts = data.data.children.map(child => child.data); console.log(posts.map(post => post.title)); > catch (error)  console.error(error); > > // Using Promise syntax: function getRedditPosts()  fetch('https://www.reddit.com/r/all/top.json?limit=10') .then(response => response.json()) .then(data =>  const posts = data.data.children.map(child => child.data); console.log(posts.map(post => post.title)); >) .catch(error => console.error(error)); >

Using .text()

Use this method when you want to get the response body as a plain text string, regardless of the content type. This is useful for debugging purposes or when you need to process the text yourself. For example, you can use this method to get the HTML source code of a web page or the XML data of an RSS feed.

Here’s an example of making a request to the GitHub API and displaying the contents of a file using the .text() method.

async function displayFileContentsAsync()  try  const response = await fetch('https://api.github.com/repos/github/gitignore/contents/Node.gitignore'); const text = await response.text(); console.log(text); > catch (error)  console.error(error); > > // Using Promise syntax: function displayFileContentsPromise()  fetch('https://api.github.com/repos/github/gitignore/contents/Node.gitignore') .then(response => response.text()) .then(text => console.log(text)) .catch(error => console.error(error)); >

Using .blob()

Use this method when you want to get the response body as a Blob object containing binary data. This is useful for working with data that is not text-based, such as images, videos, audio, or PDF files. For example, you can use this method to get an image from an image API or a PDF file from a document API.

Here’s an example of making a request to an image file on a server using the .blob() method:

async function displayImageAsync()  try  const response = await fetch('https://www.example.com/image.jpg'); const blob = await response.blob(); const url = URL.createObjectURL(blob); const img = document.createElement('img'); img.src = url; document.body.appendChild(img); > catch (error)  console.error(error); > > // Using Promise syntax: function displayImagePromise()  fetch('https://www.example.com/image.jpg') .then(response => response.blob()) .then(blob =>  const url = URL.createObjectURL(blob); const img = document.createElement('img'); img.src = url; document.body.appendChild(img); >) .catch(error => console.error(error)); >

Using .arrayBuffer()

Use this method when you want to get the response body as an ArrayBuffer object containing raw bytes. This is useful for working with data that requires low-level manipulation, such as encryption, compression, or decoding. For example, you can use this method to get a ZIP file from a file API or a WAV file from an audio API.

Here’s an example of making a request to an audio file on a server using the .arrayBuffer() method:

async function playAudioAsync()  try  const response = await fetch('https://www.example.com/audio.mp3'); const arrayBuffer = await response.arrayBuffer(); const audioBuffer = await new AudioContext().decodeAudioData(arrayBuffer); const source = new AudioBufferSourceNode(new AudioContext(),  buffer: audioBuffer >); source.connect(new AudioContext().destination); source.start(0); > catch (error)  console.error(error); > > // Using Promise syntax: function playAudioPromise()  fetch('https://www.example.com/audio.mp3') .then(response => response.arrayBuffer()) .then(arrayBuffer => new AudioContext().decodeAudioData(arrayBuffer)) .then(audioBuffer =>  const source = new AudioBufferSourceNode(new AudioContext(),  buffer: audioBuffer >); source.connect(new AudioContext().destination); source.start(0); >) .catch(error => console.error(error)); >

Using .formData()

Use this method when you want to get the response body as a FormData object containing form data. This is useful for working with data that is submitted using HTML forms, such as multipart/form-data or application/x-www-form-urlencoded . For example, you can use this method to get the user input from a contact form or a file upload form.

This method is rarely used because most APIs do not return form data as a response, but rather JSON or XML data. Also, FormData objects are not easy to inspect or manipulate, as they do not have a built-in way to iterate over their entries or convert them to other formats.

However it is particularly useful in the context of service workers due to their ability to intercept network requests and manipulate their data.

Service workers are scripts that run in the background of a web application and can intercept and handle network requests. By using the .formData() method, you can intercept a form submission request, modify the form data, and then send the modified form data to the server. This can be useful for a variety of purposes, such as logging form data, adding extra fields to the form data, or filtering sensitive data.

Here’s an example of a service worker intercepting a form submission request and modifying the form data using the .formData() method:

self.addEventListener('fetch', event =>  // Intercept form submission requests if (event.request.method === 'POST' && event.request.headers.get('Content-Type') === 'application/x-www-form-urlencoded')  event.respondWith(handleFormSubmission(event.request)); > >); async function handleFormSubmission(request)  // Parse the form data from the request body const formData = await request.formData(); // Modify the form data formData.append('extra-field', 'extra-value'); // Create a new request with the modified form data const newRequest = new Request(request.url,  method: request.method, headers: request.headers, body: new URLSearchParams(formData) >); // Make the modified request to the server return fetch(newRequest); >

Источник

Fetch: ход загрузки

Метод fetch позволяет отслеживать процесс получения данных.

Заметим, на данный момент в fetch нет способа отслеживать процесс отправки. Для этого используйте XMLHttpRequest, позже мы его рассмотрим.

Чтобы отслеживать ход загрузки данных с сервера, можно использовать свойство response.body . Это ReadableStream («поток для чтения») – особый объект, который предоставляет тело ответа по частям, по мере поступления. Потоки для чтения описаны в спецификации Streams API.

В отличие от response.text() , response.json() и других методов, response.body даёт полный контроль над процессом чтения, и мы можем подсчитать, сколько данных получено на каждый момент.

Вот примерный код, который читает ответ из response.body :

// вместо response.json() и других методов const reader = response.body.getReader(); // бесконечный цикл, пока идёт загрузка while(true) < // done становится true в последнем фрагменте // value - Uint8Array из байтов каждого фрагмента const = await reader.read(); if (done) < break; >console.log(`Получено $ байт`) >

Результат вызова await reader.read() – это объект с двумя свойствами:

  • done – true , когда чтение закончено, иначе false .
  • value – типизированный массив данных ответа Uint8Array .

Streams API также описывает асинхронный перебор по ReadableStream , при помощи цикла for await..of , но он пока слабо поддерживается (см. задачи для браузеров), поэтому используем цикл while .

Мы получаем новые фрагменты данных в цикле, пока загрузка не завершится, то есть пока done не станет true .

Чтобы отслеживать процесс загрузки, нам нужно при получении очередного фрагмента прибавлять его длину value к счётчику.

Вот полный рабочий пример, который получает ответ сервера и в процессе получения выводит в консоли длину полученных данных:

// Шаг 1: начинаем загрузку fetch, получаем поток для чтения let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100'); const reader = response.body.getReader(); // Шаг 2: получаем длину содержимого ответа const contentLength = +response.headers.get('Content-Length'); // Шаг 3: считываем данные: let receivedLength = 0; // количество байт, полученных на данный момент let chunks = []; // массив полученных двоичных фрагментов (составляющих тело ответа) while(true) < const = await reader.read(); if (done) < break; >chunks.push(value); receivedLength += value.length; console.log(`Получено $ из $`) > // Шаг 4: соединим фрагменты в общий типизированный массив Uint8Array let chunksAll = new Uint8Array(receivedLength); // (4.1) let position = 0; for(let chunk of chunks) < chunksAll.set(chunk, position); // (4.2) position += chunk.length; >// Шаг 5: декодируем Uint8Array обратно в строку let result = new TextDecoder("utf-8").decode(chunksAll); // Готово! let commits = JSON.parse(result); alert(commits[0].author.login);

Разберёмся, что здесь произошло:

  1. Мы обращаемся к fetch как обычно, но вместо вызова response.json() мы получаем доступ к потоку чтения response.body.getReader() . Обратите внимание, что мы не можем использовать одновременно оба эти метода для чтения одного и того же ответа: либо обычный метод response.json() , либо чтение потока response.body .
  2. Ещё до чтения потока мы можем вычислить полную длину ответа из заголовка Content-Length . Он может быть нечитаемым при запросах на другой источник (подробнее в разделе Fetch: запросы на другие сайты) и, в общем-то, серверу необязательно его устанавливать. Тем не менее, обычно длина указана.
  3. Вызываем await reader.read() до окончания загрузки. Всё, что получили, мы складываем по «кусочкам» в массив chunks . Это важно, потому что после того, как ответ получен, мы уже не сможем «перечитать» его, используя response.json() или любой другой способ (попробуйте – будет ошибка).
  4. В самом конце у нас типизированный массив – Uint8Array . В нём находятся фрагменты данных. Нам нужно их склеить, чтобы получить строку. К сожалению, для этого нет специального метода, но можно сделать, например, так:
    1. Создаём chunksAll = new Uint8Array(receivedLength) – массив того же типа заданной длины.
    2. Используем .set(chunk, position) для копирования каждого фрагмента друг за другом в него.

    В итоге у нас есть результат (строки или Blob , смотря что удобно) и отслеживание прогресса получения.

    На всякий случай повторимся, что здесь мы рассмотрели, как отслеживать процесс получения данных с сервера, а не их отправки на сервер. Для отслеживания отправки у fetch пока нет способа.

    Источник

Оцените статью