#Что происходит и как распознать неисправность
В отличие от Failed to fetch, здесь сетевой запрос завершился и объект Response получен. Метод .json() читает тело и разбирает его как JSON; SyntaxError означает неверный формат тела: HTML ошибки, пустой ответ, повреждённая JSON-строка либо неверные кавычки.
#Как отличить причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| В ответе HTML вместо JSONПрокси или сервер вернул страницу входа/ошибки. | В «Ответ» начинается <!doctype html> или <html>. | Проверяйте status и Content-Type до разбора. |
| Ответ без телаСервер отправил 204 No Content либо пустую строку. | В «Сеть» нет тела ответа. | Не вызывайте json() для ожидаемо пустого ответа. |
| Сервер возвращает некорректный JSONСтрока содержит лишнюю запятую, комментарий, обрезанные байты. | Во вкладке Response видна строка, нарушающая JSON. | Исправьте сериализацию на стороне API. |
#Пошаговая диагностика и исправление
- Воспроизведите запрос и откройте сетевые сведенияОткройте страницу, нажмите F12 → вкладка «Сеть», повторите действие, выберите нужный запрос fetch/XHR. Посмотрите код статуса и вкладку «Ответ». Если запроса нет или он заблокирован CORS, сначала устраните сетевую ошибку — этот материал относится только к полученному ответу.
- Отличите успешный HTTP от ответа с ошибкойВ строке запроса проверьте Status: 200, 204, 401, 404 или 500. fetch не отклоняет промис автоматически на HTTP 4xx/5xx; проверять
response.okнужно в вашем коде. Если статус 302 и затем HTML входа, решайте вопрос авторизации, а не парсинга JSON. - Проверьте MIME-тип и первые символы телаВо вкладке «Заголовки» найдите Response Headers →
Content-Type. Для JSON ожидаетсяapplication/jsonили совместимый тип. В «Ответ» посмотрите начало содержимого:<указывает на HTML, пустота — на отсутствие тела. Если ответ содержит чувствительные данные, не выкладывайте его целиком в переписку. - Отладьте тело без повторного чтенияВ тестовом обработчике получите
const text = await response.clone().text()доresponse.json()— clone создаёт вторую ветвь потока. Выведите первые безопасные символы/длину, но не токены, пароль или личные данные. Не вызывайте сначала response.text(), а затем response.json() на том же объекте: поток читается один раз. - Обработайте пустые успешные ответыЕсли API по контракту возвращает 204 No Content, проверяйте
response.status === 204и завершайте обработку безjson(). Если по контракту должен быть JSON, попросите разработчика сервера отдавать корректное тело и Content-Type; не преобразовывайте пустую строку в фиктивный объект для всех ситуаций. - Почините генерацию JSON на сервереЕсли сервер ваш, откройте обработчик маршрута и убедитесь, что он сериализует объект средствами языка (например,
json_encodeв PHP) и не печатает предупреждения, HTML или лишние пробелы перед JSON, где это важно для контракта. Проверьте ошибку на тестовом окружении; важные сведения об исключениях держите в серверных журналах, а не в клиентском ответе. - Проверьте исправление и обработку неуспехаПерезагрузите страницу и повторите запрос. Ожидается валидный JSON, успешно обработанный
await response.json(). Отдельно проверьте 204, 401 и ошибку 500: интерфейс должен показывать понятное сообщение. При регрессии восстановите прежний клиентский обработчик и передайте разработчику API код статуса и тип ответа.
#Команды и примеры для проверки
async function loadData(url) {
const response = await fetch(url);
if (response.status === 204) return null;
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const kind = response.headers.get("content-type") || "";
if (!kind.includes("json")) throw new Error("Сервер вернул не JSON");
return response.json();
}#Как проверить результат и что делать дальше
Если тело валидно и содержит ожидаемую структуру, JSON читается без SyntaxError. Если ошибка сохраняется, храните минимальный обезличенный образец ответа и сверяйте схему API; не выводите в лог секреты пользователя.