1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7

# конспект · шаг 7 из 7

Конспект: протокол под nginx

выжимка - её можно унести в заметки

Решение №0: на чём вообще всё держится. Протокол, поверх которого настраивается всё остальное в курсе.

Четыре части сообщения

строка запроса    GET /catalog/42?sort=price HTTP/1.1
заголовки         Host: shop.local
                  User-Agent: curl/8.22.0
пустая строка     ← признак «заголовки кончились»
тело              у GET его нет

У ответа то же самое, только первая строка другая: HTTP/1.1 200 OK.

Адрес по частям

Часть Куда попадает
схема https:// в запрос не едет; решает порт и шифрование
хост shop.local заголовок Host
путь /catalog/42 первая строка запроса; по нему выбирается location
параметры ?sort=price там же; в выборе location не участвуют
фрагмент #otzyvy остаётся в браузере, на сервер не уходит

Три переменные над одним адресом:

Переменная Что в ней
$request_uri как прислали, вместе с ? и кодированием
$uri раскодированный и нормализованный путь
$args параметры; не раскодируются вовсе

В редиректах нужен $request_uri - иначе теряются метки и параметры поиска.

Коды по классам

Класс Смысл Кто обычно назначает
1xx ответ ещё не окончательный nginx; в access_log не попадает
2xx готово (200, 204 без тела, 206 кусок) файл - nginx, данные - приложение
3xx иди туда; плюс 304 «твоя копия годится» чаще nginx
4xx так спросить нельзя оба; кто - видно по upstream в логе
5xx сломалось на сервере 502 и 504 - всегда nginx
  • У 204 и 304 тела нет по определению, у редиректа обязателен Location.
  • return 301 /path nginx достраивает до абсолютного адреса из Host.
  • 301 и 308 постоянные, браузер их запоминает; 307 и 308 сохраняют метод.

Соединение

  • Каждый круг по сети стоит времени: TCP - один, TLS 1.3 - ещё один, TLS 1.2 - два, запрос - последний. Замер при задержке 50 мс: http 102 мс, https 163 мс, https с TLS 1.2 - 210 мс.
  • Соединение живёт дольше запроса: keepalive_timeout, по умолчанию 75 с.
  • Где кончается ответ, говорят Content-Length (длина известна) или Transfer-Encoding: chunked (длина неизвестна). Без одного из них соединение не переиспользовать.
  • В HTTP/1.1 очередь в соединении одна - отсюда HTTP/2.

Заголовки при проксировании

Участковые (hop-by-hop) - не пересылаются никогда: Connection, Keep-Alive, Upgrade, Transfer-Encoding, TE, Trailer, Proxy-Authenticate, Proxy-Authorization.

Всё остальное сквозное и обязано дойти до приложения без изменений.

proxy_set_header Host $host;          # иначе бэкенд увидит имя upstream
proxy_set_header Accept-Encoding "";  # пустое значение = удалить заголовок

Ловушки джокера

  • Имя заголовка с подчёркиванием отбрасывается молча. X-Api_Key не дойдёт ни до переменной, ни до бэкенда, и строки в логе не будет. Лечится underscores_in_headers on, но правильнее переименовать в X-Api-Key.
  • proxy_set_header наследуется «всё или ничего». Одна своя директива в location отменяет все унаследованные - вместе с заботливо поставленным Host.
  • Одно имя заголовка может прийти дважды. Бэкенду уедут обе строки, а в переменной nginx они склеятся через запятую (a, b) - наивная проверка «равно a» так обходится.
  • %2F в пути становится настоящим слешем до выбора location: deny не обойти, но и слеш внутри имени файла не сохранить.
  • Фрагмент после # в конфиге недоступен - его нет в запросе.
  • Слишком длинный адрес - 414, и объяснение пишется на уровне info.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.