Введение в HTTP-заголовки
HTTP-заголовки — это способ передать дополнительную информацию между клиентом и сервером, например, о типе отправляемых данных или авторизации пользователя. В браузере, скажем, вы можете зайти в DevTools → Network и посмотреть заголовки любого запроса.
Пример типичных заголовков
Content-Type: указывает тип данных в теле запроса. Например,application/jsonдля JSON илиmultipart/form-dataдля файлов.Authorization: используется для отправки токенов авторизации.Accept: сообщает серверу, какие форматы данных клиент может обработать, например,application/json.
Давайте посмотрим на пример простого GET-запроса с настройкой заголовков:
// Пример использования заголовков в GET-запросе
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'GET', // Указываем метод запроса
headers: {
'Content-Type': 'application/json', // Мы ожидаем JSON
'Authorization': 'Bearer your_token_here' // Токен для авторизации
}
})
.then(response => response.json()) // Преобразуем ответ в JSON
.then(data => console.log(data)) // Выводим результат в консоль
.catch(error => console.error('Ошибка:', error)); // Обрабатываем ошибки
Обратите внимание на то, как мы добавляем заголовки в запрос. Они задаются в объекте headers.
Работа с телом запроса: JSON и FormData
Заголовки заголовками, а тело запроса — это реальное "мясо" HTTP-запроса. В рамках REST API чаще всего отправляются данные в формате JSON или через форму (FormData, если вы работаете с файлами).
Пример отправки данных в JSON формате
Чаще всего сервер ожидает, что данные будут отправлены в формате JSON. Вот как это сделать:
// Отправка POST-запроса с JSON-данными
const postData = async () => {
const data = { title: 'foo', body: 'bar', userId: 1 };
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST', // Указываем метод POST
headers: {
'Content-Type': 'application/json', // Заголовок для JSON
},
body: JSON.stringify(data), // Преобразуем объект в строку JSON
});
const result = await response.json(); // Преобразуем ответ
console.log('Ответ от сервера:', result);
};
postData();
Пример использования FormData для отправки файлов
FormData — это удобный способ отправлять файлы вместе с другими данными, например, изображение профиля пользователя:
// Отправка файла с использованием FormData
const uploadFile = async (file: File) => {
const formData = new FormData();
formData.append('profileImage', file); // Добавляем файл
formData.append('userId', '12345'); // Добавляем дополнительные данные
const response = await fetch('https://example.com/upload', {
method: 'POST',
body: formData, // Передаём форму как тело запроса
});
const result = await response.json();
console.log('Файл загружен:', result);
};
Здесь мы не указываем Content-Type, потому что браузер автоматически добавляет нужный заголовок для FormData.
Обработка ошибок
Ошибки — это как баги в коде: они всегда найдут способ вас достать. Но с ними можно работать красиво и предсказуемо.
Вот как можно обработать ошибки при выполнении запроса:
fetch('https://jsonplaceholder.typicode.com/posts/invalid-endpoint', {
method: 'GET',
})
.then(response => {
if (!response.ok) {
// Проверяем код статуса
throw new Error(`HTTP ошибка! Код: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Ошибка запроса:', error));
Обратите внимание на проверку response.ok. Это Версальский договор между программистом и сервером: если что-то пошло не так (например, 404), мы это перехватим.
Создание хука для работы с запросами
Процедура выполнения запросов часто повторяется. Поэтому логично вынести её в пользовательский хук.
Вот пример простого хука для выполнения запросов:
import { useState } from 'react';
// Пользовательский хук
export const useFetch = (url: string) => {
const [data, setData] = useState<any>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const fetchData = async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Ошибка! Код: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err: any) {
setError(err.message);
} finally {
setIsLoading(false);
}
};
return { data, isLoading, error, fetchData };
};
Теперь можно использовать этот хук в любом компоненте. Например:
import React, { useEffect } from 'react';
import { useFetch } from './hooks/useFetch';
const PostList: React.FC = () => {
const { data, isLoading, error, fetchData } = useFetch('https://jsonplaceholder.typicode.com/posts');
useEffect(() => {
fetchData();
}, []); // Загружаем данные при первом рендере
if (isLoading) return <p>Загрузка данных...</p>;
if (error) return <p>Ошибка: {error}</p>;
return (
<ul>
{data.map((post: { id: number; title: string }) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
};
export default PostList;
Советы по улучшению пользовательского опыта (UX)
- Индикаторы загрузки: всегда показывайте пользователю, что данные загружаются. Никому не нравится "белый экран ожидания".
- Обработка ошибок: никогда не пугайте пользователя техномантрами вроде "SyntaxError: Unexpected token <". Лучше показывайте дружелюбные сообщения.
- Кэширование данных: если ваши данные редко меняются, можно сохранять результат запроса в
localStorageилиRedux, чтобы избежать лишних запросов.
Вот и всё на сегодня. Теперь вы умеете загружать данные, отправлять их на сервер и даже обрабатывать ошибки запроса. И помните: хороший код — это не только рабочий код, но и тот, который понимают ваши коллеги. Ну или вы сами, спустя три месяца. 😉
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ