Кратко
СкопированоС помощью глобальной функции fetch можно выполнять HTTP-запросы — как получать, так и отправлять данные. Функция возвращает промис, который резолвится в объект ответа, где находится дополнительная информация (статус ответа, заголовки) и ответ на запрос.
Пример
СкопированоРассмотрим несколько примеров использования fetch.
Проверим доступ к тестовому API с помощью GET-запроса:
fetch('https://dummyjson.com/test') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error.message))// { status: 'ok', method: 'GET' }
fetch('https://dummyjson.com/test')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error.message))
// { status: 'ok', method: 'GET' }
А вот такой же запрос с синтаксисом async/await:
try { const response = await fetch('https://dummyjson.com/test') const data = await response.json() console.log(data)} catch (error) { console.error(error.message)}// { status: 'ok', method: 'GET' }
try {
const response = await fetch('https://dummyjson.com/test')
const data = await response.json()
console.log(data)
} catch (error) {
console.error(error.message)
}
// { status: 'ok', method: 'GET' }
Отправим данные с помощью POST-запроса:
try { const response = await fetch('https://dummyjson.com/todos/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ todo: 'Выучить С++ за 21 день', userId: '42', completed: false }) }) const data = await response.json() console.log(data)} catch (error) { console.error(error.message)}// {// id: 255,// todo: 'Выучить С++ за 21 день',// completed: false,// userId: '42'// }
try {
const response = await fetch('https://dummyjson.com/todos/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
todo: 'Выучить С++ за 21 день',
userId: '42',
completed: false
})
})
const data = await response.json()
console.log(data)
} catch (error) {
console.error(error.message)
}
// {
// id: 255,
// todo: 'Выучить С++ за 21 день',
// completed: false,
// userId: '42'
// }
Как пишется
Скопировано
fetch(resource, options)
fetch(resource, options)
Функция fetch принимает два параметра:
resource— строка, содержащая URL-адрес, по которому нужно сделать запрос, или специальный Request-объект, хранящий данные запроса;options(необязательный) — объект конфигурации, в котором можно настроить метод и тело запроса, заголовки и многое другое.
Для выполнения GET-запроса к серверу по url-адресу можно использовать краткий синтаксис: fetch.
Функция fetch возвращает Promise, который:
- при успешном выполнении запроса резолвится в объект
Response, представляющий ответ от сервера; - будет отклонён (rejected) при возникновении сетевых ошибок (например: нет доступа к сети, CORS‑блокировка).
При вызове fetch будет брошено исключение Type если:
- указан некорректный URL-адрес;
- объект конфигурации options содержит недопустимые параметры;
Как понять
СкопированоФункция fetch предназначена для выполнения HTTP-запросов. Раньше для этой цели использовался XML, однако fetch более гибкое и универсальное решение.
В отличие от XMLHttpRequest API, где результат запроса обрабатывается с помощью колбэков, fetch() использует Promise. Это позволяет упростить и переиспользовать код, отделив логику обработки результата от выполнения запроса.
Гибкость интерфейса fetch основана на использовании специальных объектов:
- Request, хранит информацию о запросе (URL-адрес, HTTP-метод, формат передаваемых данных, данные и заголовки запроса );
- Response, содержит данные о результате и методы обработки ответа.
Глобальная функция fetch не описывается спецификацией ECMAScript и доступна в браузере как часть Web API, а вне браузера (Node.js, Deno, Bun) как часть runtime API.
Формирование и отправка запроса
СкопированоУказать HTTP-метод, добавить заголовки и тело запроса, можно c помощью объекта options:
// Данные для отправки на серверconst newPost = { title: 'foo', userId: 1,}fetch('https://jsonplaceholder.typicode.com/posts', { method: 'POST', // Здесь так же могут быть GET, PUT, DELETE // Тело запроса в JSON-формате body: JSON.stringify(newPost), headers: { // Добавляем необходимые заголовки 'Content-type': 'application/json; charset=UTF-8', }}) .then((response) => response.json()) .then((data) => { console.log(data) // {title: "foo", userId: 1, id: 101} })
// Данные для отправки на сервер
const newPost = {
title: 'foo',
userId: 1,
}
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST', // Здесь так же могут быть GET, PUT, DELETE
// Тело запроса в JSON-формате
body: JSON.stringify(newPost),
headers: {
// Добавляем необходимые заголовки
'Content-type': 'application/json; charset=UTF-8',
}
})
.then((response) => response.json())
.then((data) => {
console.log(data)
// {title: "foo", userId: 1, id: 101}
}
)
Выполним тот же запрос, но с явным созданием объекта Request, принимающего те же параметры, что и fetch:
const newPost = { title: 'foo', userId: 1,}// Создаём объект Requestconst request = new Request( 'https://jsonplaceholder.typicode.com/posts', { method: 'POST', body: JSON.stringify(newPost), headers: { 'Content-type': 'application/json; charset=UTF-8', }})// Выполняем запросfetch(request) .then((response) => response.json()) .then((data) => { console.log(data) // {title: "foo", userId: 1, id: 101} })
const newPost = {
title: 'foo',
userId: 1,
}
// Создаём объект Request
const request = new Request(
'https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify(newPost),
headers: {
'Content-type': 'application/json; charset=UTF-8',
}
})
// Выполняем запрос
fetch(request)
.then((response) => response.json())
.then((data) => {
console.log(data)
// {title: "foo", userId: 1, id: 101}
}
)
Объект Request помогает разделять логику формирования и выполнения запросов, позволяя динамически формировать и изменять параметры запроса.
Если передать в fetch оба параметра, то можно изменить параметры запроса при отправке:
// Создаём объект Request c данными { title: 'bar', userId: 123 }const request = new Request( 'https://jsonplaceholder.typicode.com/posts', { method: 'POST', body: JSON.stringify({ title: 'bar', userId: 123, }), headers: { 'Content-type': 'application/json; charset=UTF-8', }})fetch(request, { // Передаём в options данные { title: 'baz', userId: 42 } body: JSON.stringify({ title: 'baz', userId: 42, }),}) .then((response) => response.json()) .then((data) => { console.log(data) // {title: "baz", userId: 42, id: 101} })
// Создаём объект Request c данными { title: 'bar', userId: 123 }
const request = new Request(
'https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: 'bar',
userId: 123,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
}
})
fetch(request, {
// Передаём в options данные { title: 'baz', userId: 42 }
body: JSON.stringify({
title: 'baz',
userId: 42,
}),
})
.then((response) => response.json())
.then((data) => {
console.log(data)
// {title: "baz", userId: 42, id: 101}
}
)
Получение ответа
СкопированоРезультатом вызова fetch будет промис. При завершении запроса промис резолвится в объект ответа Response, который содержит информацию об ответе сервера. У этого объекта есть множество полезных полей и методов. Вот основные:
ok— принимает состояниеtrueилиfalseи сообщает об успешности запроса;status— содержит HTTP-код ответа, например: 200, 400, 404;headers— объект заголовков ответаHeaders;json— возвращает результат запроса в виде JSON;( ) text— возвращает результат запроса в виде текста;( ) blob— возвращает результат запроса в виде объекта файла;( ) array— возвращает результат запроса в виде бинарных данных.Buffer ( )
В следующем примере используем .then для обработки результата, полученного от асинхронной операции. Обработчик принимает ответ сервера и выполняет с помощью метода json преобразование тела ответа в объект JavaScript. Результат вызова json это тоже промис, поэтому отображение полученных данных будет выполнено тоже асинхронно следующим колбэком в цепочке.
fetch('http://jsonplaceholder.typicode.com/posts') .then((response) => response.json()) .then(data => console.log(data)) // [{...}, {...}, {...}, ...]
fetch('http://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then(data => console.log(data))
// [{...}, {...}, {...}, ...]
Cookies
По умолчанию fetch запросы не включают в себя cookies, и поэтому авторизованные запросы на сервере могут не пройти. Для этого необходимо добавить в настройку поле credentials:
fetch('https://somesite.com/admin', { method: 'GET', // Или same-origin, если можно делать такие запросы // только в пределах этого домена credentials: 'include',})
fetch('https://somesite.com/admin', {
method: 'GET',
// Или same-origin, если можно делать такие запросы
// только в пределах этого домена
credentials: 'include',
})
Обработка ошибок
СкопированоЛюбой ответ на запрос через fetch, например, HTTP-код 400, 404 или 500, переводит Promise в состояние fulfilled. Промис перейдёт в состояние rejected только если запрос не случился из-за сбоя сети или что-то помешало выполнению fetch.
// Запрос вернёт ошибку «404 Not Found»fetch('https://jsonplaceholder.typicode.com/there-is-no-such-route').catch( () => { console.log('Error occurred!') })// Никогда не выполнится
// Запрос вернёт ошибку «404 Not Found»
fetch('https://jsonplaceholder.typicode.com/there-is-no-such-route').catch(
() => {
console.log('Error occurred!')
}
)
// Никогда не выполнится
Чтобы обработать ошибку запроса, необходимо обращать внимание на поле ok в объекте ответа Response. В случае ошибки запроса оно будет равно false.
fetch('https://jsonplaceholder.typicode.com/there-is-no-such-route') .then((response) => { // Проверяем успешность запроса и выкидываем ошибку if (!response.ok) { throw new Error('Error occurred!') } return response.json() }) // Теперь попадём сюда, так как выбросили ошибку .catch((err) => { console.log(err) })// Error: Error occurred!
fetch('https://jsonplaceholder.typicode.com/there-is-no-such-route')
.then((response) => {
// Проверяем успешность запроса и выкидываем ошибку
if (!response.ok) {
throw new Error('Error occurred!')
}
return response.json()
})
// Теперь попадём сюда, так как выбросили ошибку
.catch((err) => {
console.log(err)
}
)
// Error: Error occurred!
В большинстве случаев ошибки, возникающие при выполнении fetch(), асинхронны: промис переходит в состояние rejected. Такие ошибки можно обработать с помощью .catch. При этом при подготовке данных запроса может возникнуть и синхронная ошибка, например:
try { // Объект с циклической ссылкой const invalidBody = { key: "value" } invalidBody.self = invalidBody fetch('https://dummyjson.com/posts/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, // Пытаемся преобразовать объект в JSON // Здесь возникнет синхронная ошибка body: JSON.stringify(invalidBody) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.log('Асинхронная ошибка:', error))} catch (error) { // Ловим синхронную ошибку console.log('Синхронная ошибка:', error.message)}// Синхронная ошибка: Converting circular structure to JSON
try {
// Объект с циклической ссылкой
const invalidBody = { key: "value" }
invalidBody.self = invalidBody
fetch('https://dummyjson.com/posts/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
// Пытаемся преобразовать объект в JSON
// Здесь возникнет синхронная ошибка
body: JSON.stringify(invalidBody)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log('Асинхронная ошибка:', error))
} catch (error) {
// Ловим синхронную ошибку
console.log('Синхронная ошибка:', error.message)
}
// Синхронная ошибка: Converting circular structure to JSON
Оборачивая код подготовки данных и выполнения запроса в try/catch мы можем быть уверены, что любая ошибка будет обработана.
На практике
Скопированосоветует
СкопированоОтмена запроса
СкопированоИногда может возникнуть необходимость прервать запрос, например, когда авторизация пользователя просрочена или пользователь самостоятельно хочет отменить запрос (отменил скачивание файла).
const controller = new AbortController()function fetchData() { return fetch('http://jsonplaceholder.typicode.com/posts', { signal: controller.signal, }) .then((response) => response.json()) .catch((e) => { console.log(e) } )}fetchData()// Если запрос ещё не выполнился, то он будет прерван.// Прерванный fetch вернёт Promise с ошибкойcontroller.abort()
const controller = new AbortController()
function fetchData() {
return fetch('http://jsonplaceholder.typicode.com/posts', {
signal: controller.signal,
})
.then((response) => response.json())
.catch((e) => {
console.log(e)
}
)
}
fetchData()
// Если запрос ещё не выполнился, то он будет прерван.
// Прерванный fetch вернёт Promise с ошибкой
controller.abort()
Запрос не выполнится, в консоли будет ошибка The user aborted a request. Если заглянуть в инструменты разработчика, то там можно увидеть отменённый статус у запроса.

Загрузка файла на сервер
СкопированоС помощью fetch можно загружать файлы на сервер, например, когда пользователь хочет загрузить свой аватар в профиль. Отправку файлов можно осуществлять с помощью специального объекта Form. Покажем на примере обработчика отправки формы:
<form id="form"> <input type="file" id="avatar"> <button type="submit">Загрузить</button></form>
<form id="form">
<input type="file" id="avatar">
<button type="submit">Загрузить</button>
</form>
// Находим элемент с файломconst fileInput = document.getElementById('avatar')const form = document.getElementById('form')function handleSubmit(event) { event.preventDefault() const formData = new FormData() // Добавляем файлы из инпута к данным for (let i = 0; i < fileInput.files.length; i++) { const file = fileInput.files[i] formData.append('avatar', file, file.name) } // Отправляем файлы на сервер fetch('https://backend.com/api/upload', { method: "POST", body: formData, })}form.addEventListener('submit', handleSubmit)
// Находим элемент с файлом
const fileInput = document.getElementById('avatar')
const form = document.getElementById('form')
function handleSubmit(event) {
event.preventDefault()
const formData = new FormData()
// Добавляем файлы из инпута к данным
for (let i = 0; i < fileInput.files.length; i++) {
const file = fileInput.files[i]
formData.append('avatar', file, file.name)
}
// Отправляем файлы на сервер
fetch('https://backend.com/api/upload', {
method: "POST",
body: formData,
})
}
form.addEventListener('submit', handleSubmit)
Скачивание данных с результатом прогресса
СкопированоЧтобы получать текущий прогресс скачивания файла или любых других данных, используйте свойство body объекта Response, который возвращается в Promise после вызова fetch. Поле body является «потоком для чтения» (Readable Stream). Это специальный объект, который даёт возможность получать информацию по частям, по мере её поступления на клиент.
Попробуем таким образом загрузить милое видео, как белый котик дружит с огромным псом.
fetch('https://i.imgur.com/C5QXZ7u.mp4').then(async (response) => { let received = 0 // Получаем поток в переменную const reader = response.body.getReader() // Считываем общую длину данных const contentLength = parseInt(response.headers.get('Content-Length'), 10) while (true) { // После вызова read() возвращается объект, в котором // done — boolean-значение о том, закончилась ли информация, // value — массив байт, которые пришли в этот раз const { done, value } = await reader.read() if (done) { console.log('Получено 100%') break } received += (value.length / contentLength) * 100 const result = Math.floor(received) if (result < 100) { console.log(`Получено ${result}%`) } }})
fetch('https://i.imgur.com/C5QXZ7u.mp4').then(async (response) => {
let received = 0
// Получаем поток в переменную
const reader = response.body.getReader()
// Считываем общую длину данных
const contentLength = parseInt(response.headers.get('Content-Length'), 10)
while (true) {
// После вызова read() возвращается объект, в котором
// done — boolean-значение о том, закончилась ли информация,
// value — массив байт, которые пришли в этот раз
const { done, value } = await reader.read()
if (done) {
console.log('Получено 100%')
break
}
received += (value.length / contentLength) * 100
const result = Math.floor(received)
if (result < 100) {
console.log(`Получено ${result}%`)
}
}
})