← Назад к вопросам

Как понять как завершился REST-запрос?

1.8 Middle🔥 191 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как понять как завершился REST-запрос?

HTTP статус-коды

REST-запрос завершается с определённым статус-кодом, который указывает на результат:

2xx — Success (успешно)

  • 200 OK — запрос успешен, ответ содержит данные
  • 201 Created — ресурс создан (обычно для POST)
  • 204 No Content — успех, но нет данных в ответе (обычно для DELETE)

3xx — Redirection (перенаправление)

  • 301 Moved Permanently — ресурс переехал навсегда
  • 307 Temporary Redirect — временное перенаправление

4xx — Client Error (ошибка клиента)

  • 400 Bad Request — неверный формат запроса
  • 401 Unauthorized — не авторизован
  • 403 Forbidden — доступ запрещён
  • 404 Not Found — ресурс не найден
  • 422 Unprocessable Entity — логическая ошибка (валидация не пройдена)
  • 429 Too Many Requests — слишком много запросов (rate limit)

5xx — Server Error (ошибка сервера)

  • 500 Internal Server Error — внутренняя ошибка
  • 503 Service Unavailable — сервис недоступен

Методы проверки в коде

// === FETCH API ===
async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`);
  
  // Способ 1: Проверить status напрямую
  if (response.status === 200) {
    const data = await response.json();
    return { success: true, data };
  }
  
  // Способ 2: Использовать response.ok (true для 200-299)
  if (response.ok) {
    const data = await response.json();
    return { success: true, data };
  } else {
    const error = await response.json();
    return { success: false, error };
  }
}

// === AXIOS ===
import axios from 'axios';

async function fetchUserWithAxios(id) {
  try {
    // Axios автоматически выбрасывает ошибку для статусов вне 2xx
    const { data, status } = await axios.get(`/api/users/${id}`);
    console.log(`Запрос успешен, код ${status}`);
    return data;
  } catch (error) {
    // Ошибка сети или статус >= 400
    if (error.response) {
      // Сервер вернул ошибку (4xx/5xx)
      console.error(`Ошибка ${error.response.status}: ${error.response.data.message}`);
    } else if (error.request) {
      // Запрос отправлен, но ответа нет (сеть)
      console.error('Нет ответа от сервера');
    } else {
      // Ошибка при создании запроса
      console.error('Ошибка запроса:', error.message);
    }
    throw error;
  }
}

// === СОВРЕМЕННЫЙ ПОДХОД: Типизированный wrapper ===
type ApiResponse<T> = 
  | { ok: true; data: T; status: number }
  | { ok: false; error: string; status: number };

async function apiRequest<T>(
  url: string,
  options?: RequestInit
): Promise<ApiResponse<T>> {
  try {
    const response = await fetch(url, options);
    const data = await response.json();

    if (response.ok) {
      return { ok: true, data, status: response.status };
    } else {
      return { ok: false, error: data.message || 'Unknown error', status: response.status };
    }
  } catch (error) {
    return { ok: false, error: 'Network error', status: 0 };
  }
}

// Использование:
const result = await apiRequest<User>('/api/users/123');
if (result.ok) {
  console.log('Пользователь:', result.data);
} else {
  console.error('Ошибка:', result.error);
}

Проверка в React компоненте

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUser = async () => {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch(`/api/users/${userId}`);

        // Проверяем статус
        if (!response.ok) {
          // Обработка конкретных ошибок
          switch (response.status) {
            case 404:
              setError('Пользователь не найден');
              break;
            case 401:
              setError('Необходима авторизация');
              break;
            case 500:
              setError('Ошибка сервера, попробуйте позже');
              break;
            default:
              setError(`Ошибка ${response.status}`);
          }
          return;
        }

        const data = await response.json();
        setUser(data);
      } catch (err) {
        // Сетевая ошибка или ошибка парсинга JSON
        setError('Ошибка сети');
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    fetchUser();
  }, [userId]);

  if (loading) return <p>Загрузка...</p>;
  if (error) return <p style={{ color: 'red' }}>{error}</p>;
  if (!user) return <p>Нет данных</p>;

  return <div>{user.name}</div>;
}

Headers ответа и их значение

async function analyzeResponse() {
  const response = await fetch('/api/data');

  // Полезные headers:
  console.log(response.headers.get('content-type')); // 'application/json'
  console.log(response.headers.get('content-length')); // размер в байтах
  console.log(response.headers.get('cache-control')); // кэширование
  console.log(response.headers.get('x-ratelimit-remaining')); // осталось запросов
  console.log(response.headers.get('retry-after')); // когда повторить (если 429)

  // Проверка content-type перед парсингом
  const contentType = response.headers.get('content-type');
  if (contentType && contentType.includes('application/json')) {
    const json = await response.json();
    return json;
  } else {
    const text = await response.text();
    return text;
  }
}

Debugging в DevTools

// === Вкладка Network в DevTools ===
// 1. Откройте F12 -> Network
// 2. Отправьте запрос
// 3. Кликните на запрос в списке
// 4. Справа увидите:
//    - Status (200, 404, etc.)
//    - Headers (request & response)
//    - Response body
//    - Timing (как долго загружалось)

// === Фильтрация запросов ===
// Введите в фильтр:
// status-code:404    // только ошибки
// -status-code:200   // всё кроме успехов
// /api              // только API запросы

// === Сохранение логов ===
// Кликните gear icon -> Preserve log (сохранять при навигации)