Заголовки играют важную роль в работе веб-приложений. Они уточняют свойства запроса или ответа, управляют кэшированием, отвечают за безопасность и помогают отслеживать проблемы. В этой статье посмотрим, как можно управлять заголовками запросов и ответов в сервере Angie.
Навигация по циклу
Настройка location в Angie. Разделение динамических и статических запросов.
Перенаправления в Angie: return, rewrite и примеры их применения.
Сжатие текста в Angie: статика, динамика, производительность.
Работа с HTTP-заголовками запроса и ответа.
Видеоверсия
Для вашего удобства подготовлена видеоверсия этой статьи, доступна на Rutube, VKVideo и YouTube.
Заголовки ответа по умолчанию
Сервер Angie устанавливает большое количество заголовков автоматически. Некоторые необходимы для корректной работы протокола, другие опциональны и могут быть отключены.
Базовый заголовок Server показывает название веб-сервера, а также может уточнять его версию. По умолчанию в заголовок включается название и версия сервера:
curl --head localhost ... Server: Angie/1.12.1 ...
Управление этим заголовком доступно через директиву server_tokens. В открытой версии доступно только отключение версии:
server_tokens off;
Также можно указывать версию сборки (параметр build). В Angie PRO доступно указание произвольной строки в этом заголовке или вообще его отключение (пустая строка).
Заголовок Etag по умолчанию добавляется для статических ресурсов, подробнее его работа разобрана в статье про клиентское кэширование. Отключить его можно директивой etag:
etag off;
Также устанавливается стандартный заголовок Date, содержащий дату сервера. Отдельно нужно сказать про заголовок Content-Type. От него зависит обработка контента браузером: показать картинку, отрисовать текст, учесть кодировку и т.д. Для статических файлов Content-Type определяется по расширению файла, в соответствии с файлом (по умолчанию /etc/angie/mime.types). Если в файле с типами не хватает записи, её можно добавить. В случае, если Content-Type не удаётся определить, используется тип по умолчанию, который задаётся директивой default_type:
default_type application/octet-stream;
При получении такого типа браузеры обычно предлагают скачать ответ как файл и не пытаются показать его содержимое.
Помимо типа в заголовке Content-Type может передаваться кодировка контента. За работу с кодировками отвечает стандартный модуль Charset. Стандартно для веб-приложений указать кодировку контента (обычно utf-8) директивой charset:
charset utf-8;
В этом случае будем получать кодировку в заголовке:
curl --head localhost ... Content-Type: text/html; charset=utf-8 ...
Сервер предоставляет возможность конвертации кодировок, для этого нужно указать исходную кодировку (source_charset) и контент будет перекодирован в целевую (charset). По умолчанию для проксированных ответов с указанной кодировкой преобразование не производится, но его можно включить директивой:
override_charset on;
Таким образом, Angie умеет тонко работать с кодировками динамических и статических ответов.
Кастомные заголовки ответа
Начнём с заголовков ответа, которые можно устанавливать стандартным модулем Headers. Типичная задача — добавить свой заголовок для ответа:
add_header Alt-Svc 'h3=":443"; ma=86400';
Директива add_header добавит заголовок в контексте указания. При наследовании применяется общее правило для директив. То есть при наличии нескольких директив на разных уровнях, применяется директива на самом вложенном контексте, директивы из внешних контекстов не применяются. Например, для сохранения дополнительного заголовка нужно дублировать директиву add_header:
server { add_header Alt-Svc 'h3=":443"; ma=86400'; location /static/ { add_header Alt-Svc 'h3=":443"; ma=86400'; add_header x-static "Static"; } }
Модуль Headers имеет еще одну директиву для управления заголовками: expires. Она выставляет заголовки Expires и Cache-Control, которые управляют клиентским кэшированием. Для быстрой настройки “вечного” кэша достаточно добавить:
location /static/ { expires max; }
Подробнее тема клиентского кэширования разобрана в статье. Более гибкое управление заголовками реализует сторонний модуль Headers-More.
Возможности модуля Headers-More
Сторонний модуль Headers-More входит в комплект модулей OpenResty. Он позволяет управлять заголовками в широких пределах, включая добавление, изменение и удаление. Полная документация доступна на странице проекта.
Установка модуля стандартна для Angie:
apt install angie-pro-module-headers-more
Подключение происходит в главном контексте конфига:
load_module modules/ngx_http_headers_more_filter_module.so;
Начнём с базового варианта установки заголовков ответа:
location /static/ { more_set_headers 'X-more1: test1' 'X-more2: test2'; }
Директива more_set_headers в примере выше устанавливает два дополнительных заголовка. Если эти же заголовки одновременно добавить стандартным модулем Headers, то получим на выходе дублирование заголовков. Для остальных заголовков директива будет переписывать их значения, а не добавлять дубликат. Если нужно именно добавить заголовок, то можно добавить параметр -a.
Модуль умеет выставлять заголовки в зависимости от типа контента (параметр -t) в ответе или кода ответа (параметр -s). Например:
location /static/ { more_set_headers -s 200 'X-more1: test1' 'X-more2: test2'; more_set_headers -t 'text/plain' 'Content-Type: text/foo'; }
В первой директиве заголовок устанавливается только для кода ответа 200, а во второй для контента с типом text/plain будет установлен заголовок Content-Type: text/foo. Условные параметры можно объединять в одной директиве и использовать несколько раз.
Следующий пример убирает заголовок ответа:
location /static/ { more_clear_headers 'Content-Type'; }
При удалении заголовков поддерживаются шаблоны в названии заголовков (символ *):
location /static/ { more_clear_headers 'X-mo*'; }
Ранее мы работали только с заголовками ответа. Модуль Headers-More содержит аналогичные директивы для работы с заголовками запроса.
location /static/ { more_set_input_headers 'X-client: test1'; more_clear_input_headers 'Accept'; }
Для заголовков запроса возможно условное использование только по заголовку запроса Content-Type (параметр -t).
Заголовки запроса и ответа в модуле Proxy
Важная часть работы с заголовками происходит в процессе проксирования запросов. Стандартный модуль Proxy позволяет довольно гибко управлять заголовками запроса и ответа проксируемого сервера. Настройка проксирования в общем рассмотрена в отдельной статье, здесь же обсудим только аспект заголовков.
Пожалуй, самая распространённая директива для работы с заголовками это proxy_set_header:
location / { proxy_pass http://localhost:8000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; }
В данном примере устанавливаются три заголовка запроса к проксируемому серверу (апстриму): Host (доменное имя), X-Forwarded-For и X-Real-IP для идентификации клиента. В зависимости от логики работы бэкенда вам понадобится один из них или все сразу.
Также как и при работе с клиентами есть набор заголовков, которые передаются по умолчанию, а также заголовки, которые наоборот сбрасываются. Например, бэкенду стандартно передаются заголовки запроса клиента, чтобы запретить это поведение можно использовать директиву proxy_pass_request_headers:
location / { proxy_pass http://localhost:8000; proxy_pass_request_headers off; proxy_pass_request_body off; }
В этом примере бэкенду не передаются заголовки запроса клиента, а также тело запроса (proxy_pass_request_body).
По умолчанию из ответа бэкенда не передаются клиенту заголовки: Date, Server, X-Pad и X-Accel-*. Если же какие-то из них нужно передать клиенту, можно указать их в директиве proxy_pass_header:
location / { proxy_pass http://localhost:8000; proxy_pass_header Date; }
Также можно запретить передачу заголовков из ответа бэкенда клиенту (proxy_hide_header):
location / { proxy_pass http://localhost:8000; proxy_hide_header Expires; }
Чуть выше мы говорили о том, что заголовки ответа бэкенда X-Accel-* не передаются клиенту по умолчанию. Но они при этом используются сервером Angie при управлении кэшированием, перенаправлениями и кодировками. Влияние этих заголовков можно отключить директивой:
location / { proxy_pass http://localhost:8000; proxy_ignore_headers X-Accel-Expires Expires Cache-Control; }
Такая конфигурация позволит Angie кэшировать ответ на диск даже при запрете в заголовках ответа бэкенда (например, с заголовком Expires: -1).
Еще две настройки, касающиеся заголовков в модуле Proxy определяют размер корзины (proxy_headers_hash_bucket_size) и максимальный размер хэш-таблиц (proxy_headers_hash_max_size) для директив proxy_hide_header и proxy_set_header. Изменять их стоит в случае ошибок при работе с заголовками, причём сначала увеличивать максимальный размер таблицы и только потом размер корзины.
Аналогичными возможностями по работе с заголовками при проксировании обладают другие модули (FastCGI, SCGI, uWSGI).
Итоги
Работа с заголовками запросов и ответов это важная часть администрирования любого веб-приложения. В этой статье мы разобрали различные решения реальных задач и возможности стандартных и сторонних модулей в области HTTP-заголовков.

