← Назад к вопросам
Как делаешь запросы на сервер?
1.3 Junior🔥 81 комментариев
#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
HTTP запросы с фронтенда: подходы и best practices
Это фундаментальная часть фронтенд разработки. Расскажу о разных подходах и их плюсах/минусах в зависимости от ситуации.
1. Fetch API (современный стандарт)
Это встроенный в браузер API для HTTP запросов:
// Базовый GET запрос
const response = await fetch('https://api.example.com/users');
const data = await response.json();
console.log(data);
// С обработкой ошибок
const fetchUsers = async () => {
try {
const response = await fetch('/api/users', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error; // Пробросить выше
}
};
// POST с данными
const createUser = async (userData) => {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
if (!response.ok) throw new Error('Failed to create user');
return response.json();
};
// DELETE
const deleteUser = async (userId) => {
const response = await fetch(`/api/users/${userId}`, {
method: 'DELETE',
});
if (!response.ok) throw new Error('Failed to delete');
};
Плюсы fetch:
- Встроен в браузер
- Использует Promise
- Легко работать с JSON
- Минимальная зависимость
Минусы fetch:
- Нет встроенного обработки timeouts
- Нужно вручную обрабатывать ошибки
- Нет встроенной retry логики
- Немного verbose синтаксис для сложных случаев
2. Axios (популярная библиотека)
Альтернатива с удобнее API:
import axios from 'axios';
// GET
const data = await axios.get('/api/users');
console.log(data.data); // Заметьте двойное .data
// POST
const response = await axios.post('/api/users', {
name: 'John',
email: 'john@example.com',
});
// Конфигурация по умолчанию
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: {
'X-Custom-Header': 'value',
},
});
// Использование
const users = await api.get('/users');
// Интерceptors (перехватчики)
api.interceptors.request.use(
(config) => {
// Добавить token перед запросом
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
},
(error) => Promise.reject(error)
);
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Handle unauthorized
redirectToLogin();
}
return Promise.reject(error);
}
);
Плюсы axios:
- Удобный API
- Встроенные timeout и retry
- Interceptors
- Отмена запросов (AbortController)
Минусы:
- Дополнительная зависимость
- Небольшой overhead
3. React-специфичные подходы
useEffect + fetch (базовый):
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true; // Для очистки
const fetchUsers = async () => {
try {
const response = await fetch('/api/users');
if (!response.ok) throw new Error('Failed');
const data = await response.json();
if (isMounted) setUsers(data); // Проверка!
} catch (err) {
if (isMounted) setError(err.message);
} finally {
if (isMounted) setLoading(false);
}
};
fetchUsers();
return () => {
isMounted = false; // Очистка при unmount
};
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
React Query / TanStack Query (рекомендуется):
Мощная библиотека для управления асинхронным состоянием:
import { useQuery, useMutation } from '@tanstack/react-query';
// Fetch данных
function UserList() {
const { data: users, isLoading, error } = useQuery({
queryKey: ['users'], // Cache key
queryFn: async () => {
const response = await fetch('/api/users');
return response.json();
},
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
// Мутация (создание/обновление)
function CreateUserForm() {
const { mutate: createUser, isPending } = useMutation({
mutationFn: (userData) =>
fetch('/api/users', {
method: 'POST',
body: JSON.stringify(userData),
}).then(r => r.json()),
onSuccess: (newUser) => {
// Автоматически обновляет кеш
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
createUser({ name: 'John' });
}}>
<button disabled={isPending}>Submit</button>
</form>
);
}
Плюсы React Query:
- Автоматическое кеширование
- Синхронизация между вкладками
- Встроенный retry
- Оптимистичные обновления
- Фоновая ре-валидация
SWR (альтернатива от Vercel):
import useSWR from 'swr';
function UserList() {
const { data: users, error } = useSWR('/api/users', fetcher);
if (!data) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
}
4. GraphQL (для современных API)
Вместо REST иногда используется GraphQL:
import { ApolloClient, gql, useQuery } from '@apollo/client';
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;
function UserList() {
const { data, loading, error } = useQuery(GET_USERS);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error</div>;
return (
<ul>
{data.users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
5. Best Practices
1. Абстракция API слоя:
// api/users.ts
const BASE_URL = process.env.REACT_APP_API_URL;
export const usersApi = {
getAll: () => fetch(`${BASE_URL}/users`).then(r => r.json()),
getById: (id) =>
fetch(`${BASE_URL}/users/${id}`).then(r => r.json()),
create: (data) =>
fetch(`${BASE_URL}/users`, {
method: 'POST',
body: JSON.stringify(data),
}).then(r => r.json()),
update: (id, data) =>
fetch(`${BASE_URL}/users/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
}).then(r => r.json()),
delete: (id) =>
fetch(`${BASE_URL}/users/${id}`, { method: 'DELETE' }),
};
// Использование
const users = await usersApi.getAll();
2. Обработка ошибок:
class ApiError extends Error {
constructor(status, message) {
super(message);
this.status = status;
}
}
const apiCall = async (url, options = {}) => {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new ApiError(
response.status,
error.message || response.statusText
);
}
return response.json();
};
3. Timeout:
const fetchWithTimeout = (url, timeout = 5000) => {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
),
]);
};
4. Retry логика:
const retryFetch = async (url, options = {}, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url, options);
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
};
5. Типизация (TypeScript):
interface User {
id: number;
name: string;
email: string;
}
const getUsers = async (): Promise<User[]> => {
const response = await fetch('/api/users');
return response.json();
};
Рекомендуемый выбор инструмента
Просто и быстро: Fetch API
↓
Есть хардкод логики: Axios
↓
Нужно кешировать + синхронизировать: React Query
↓
Модерный API с GraphQL: Apollo Client
Итог
Мой подход в production:
- API слой с функциями (api/users.ts, api/posts.ts)
- React Query для управления состоянием
- Axios с interceptors для обработки ошибок и авторизации
- TypeScript для типобезопасности
- Error boundaries для graceful error handling
Это обеспечивает надёжность, масштабируемость и удобство разработки.