DarkRiDDeR14 мин

HTTP и TLS без гадания: как разобрать 404, 503 и ошибку сертификата

СетиДиагностика

Запрос к сервису может не дойти до приложения, хотя пользователь видит обычную страницу ошибки. 404 говорит о выбранном ресурсе, 503 — о доступности обработчика, а ERR_TLS_CERT_ALTNAME_INVALID возникает ещё до HTTP. Цена смешения этих уровней — часы на исправление маршрута в коде, когда проблема находится в имени узла или на обратном прокси.

Разберём три наблюдаемых случая на одном маршруте: сначала получим ответ локального HTTP-сервера, затем отделим HTTP-статус от TLS-этапа и зафиксируем следующий запрос для проверки. Пример учебный: он не обращается к внешней сети и не выдаёт локальный результат за состояние чужой инфраструктуры.

Сначала фиксируем точку отказа

У любого запроса есть последовательность: разрешение имени, установка TCP-соединения, TLS-рукопожатие для https, отправка HTTP-запроса и чтение ответа. Важен первый наблюдаемый факт. Если клиент не смог проверить сертификат, у него нет HTTP-статуса. Если получен 404, TLS и HTTP-соединение уже состоялись, а искать нужно URI, метод или маршрутизацию.

Какой уровень проверять первым
НаблюдениеУровеньПервое действиеЧего не делать
Ошибка имени сертификатаTLSсверить host и SANне менять HTTP-заголовки
404 Not FoundHTTP-маршрутпроверить путь и методне увеличивать timeout
503 Service Unavailableобработчик или зависимостьпрочитать заголовки и логине повторять POST вслепую
Нет ответа и timeoutсеть или серверразделить connect/read timeoutне считать это 500
Схема уровней запроса: DNS, TCP, TLS, HTTP и ответ с точкой остановки диагностики.
Диаграмма показывает порядок уровней. Стрелка останавливается на первом слое, о котором есть наблюдение.

Учебный HTTP-ответ на локальном сервере

Чтобы не спорить о сообщении браузера, поднимем два endpoint в одном Node-процессе. Вход — путь запроса. Ожидаемый результат — числовой статус и тело. Такой запуск показывает семантику HTTP-ответа, но не тестирует TLS: для TLS нужен отдельный сервер с сертификатом и проверкой имени.

import { createServer } from 'node:http';

const server = createServer((request, response) => {
  if (request.url === '/health') {
    response.writeHead(200, { 'content-type': 'text/plain' });
    response.end('ok');
    return;
  }
  response.writeHead(404, { 'content-type': 'text/plain' });
  response.end('missing');
});

server.listen({ port: 0, host: '127.0.0.1' }, async () => {
  const port = server.address().port;
  const response = await fetch('http://127.0.0.1:' + port + '/missing');
  console.log(response.status, await response.text());
  server.close();
});

Запустите файл командой node check-http.mjs. В консоли будет 404 missing. Входом является только локальный путь; ожидаемый результат проверяем двумя значениями. Если изменить путь на /health, получится 200 ok. Это полезнее, чем проверять только цвет страницы: статус и тело принадлежат разным частям HTTP-контракта.

Почему 503 нельзя лечить повтором по умолчанию

503 означает, что сервер временно не может обработать запрос. Заголовок Retry-After может дать клиенту ориентир, но он не делает повтор безопасным. Для GET повтор обычно не меняет ресурс, а для POST повтор способен создать вторую запись или списать деньги повторно. Перед автоматикой нужно знать семантику метода и наличие ключа идемпотентности.

В диагностической записи сохраняйте метод, путь без секретов, статус, важные заголовки, время ожидания и первый байт ответа. Не прикладывайте токен авторизации и полные cookie. Для 503 сначала проверяется зависимость, ограничение соединений или обслуживание сервера; затем выбирается контролируемый повтор с лимитом и задержкой.

Ошибка сертификата находится до HTTP

TLS 1.3 устанавливает защищённый канал и проверяет имя узла в сертификате. Имя берётся из URL и должно совпасть с одним из значений Subject Alternative Name. Если клиент подключается к IP вместо доменного имени, использует устаревший alias или получает сертификат другого виртуального хоста, HTTP-заголовок Host проблему не исправит: запрос ещё не отправлен.

Практическая граница видна в подробном выводе клиента: после строки об успешной проверке сертификата и до ответа 404 проблема уже относится к HTTP-маршруту. Если TLS завершается исключением, статус и тело приложения искать бессмысленно. Это простое разделение экономит одну итерацию проверки.

Проверка должна разделять имя, цепочку доверия и срок действия. В учебной диагностике достаточно зафиксировать hostname, адрес назначения и текст ошибки библиотеки. Флаг вроде --insecure может подтвердить, что сервер отвечает, но он отключает проверку и не является исправлением. После такого эксперимента соединение нужно закрыть и повторить проверку с обычной валидацией.

Порядок диагностики

  1. Записать URL, метод, момент запроса и безопасный идентификатор запроса; убрать Authorization, Cookie и персональные параметры.
  2. Проверить разрешение имени и адрес назначения отдельно от приложения.
  3. Для HTTPS проверить hostname, SAN, срок действия и цепочку сертификата обычным клиентом.
  4. Только после успешного TLS посмотреть HTTP-статус, заголовок Allow, Location, Retry-After и тело.
  5. Сопоставить метод и действие: повтор разрешать только для операции с понятной идемпотентностью.
  6. Зафиксировать один следующий тест и ожидаемый результат, например «/health возвращает 200, /missing — 404».

Ограничения и следующий шаг

Локальный сервер не показывает работу CDN, DNS-балансировщика, корпоративного proxy или реального центра сертификации. Статус 404 не доказывает, что маршрут одинаково настроен во всех регионах, а 503 не называет виновную зависимость. Для этого нужны согласованные логи и сетевые наблюдения с разрешённым доступом.

Следующим шагом соберите две безопасные записи: успешный запрос к health-endpoint и один ошибочный запрос с тем же hostname. Сравните этап, статус, заголовки и время. Если различие появляется до HTTP, оставайтесь на TLS или сети; если оба запроса дошли до сервера, переходите к маршруту и контракту приложения.

Проверяемые источники

  • RFC 9110 — HTTP Semantics — IETF Standards Track, June 2022. Нужен для различения методов, статусов, заголовков, маршрутизации и ответа посредника. Граница применимости: Не объясняет конкретную конфигурацию прокси, DNS или причину ошибки в вашем сервисе.
  • RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3 — IETF Standards Track, August 2018. Нужен для разбора рукопожатия TLS 1.3, проверки имени узла и сообщения об ошибке сертификата. Граница применимости: Не подтверждает доверие к конкретному центру сертификации и не заменяет проверку ключевого материала.