Для чего используются HTTP заголовки и примеры
Что проверяют
Знаете ли вы заголовки как рабочий инструмент: кэш, авторизация, CORS, трассировка. Для Go-разработчика почти всегда идёт уточнение про net/http: как устроен http.Header и почему заголовок, выставленный в хендлере, иногда не доходит до клиента.
Как отвечать
Заголовки это метаданные запроса и ответа: что лежит в теле, кто спрашивает, можно ли кэшировать, куда идти дальше. Удобно группировать по задачам:
- формат тела:
Content-Type,Content-Length,Acceptдля выбора формата,Accept-EncodingиContent-Encodingдля gzip или brotli; - авторизация:
Authorization: Bearer ..., а в ответ401сWWW-Authenticate; - кэширование:
Cache-Control,ETagв паре сIf-None-Match, после чего сервер отвечает304без тела; - CORS:
Originв запросе,Access-Control-Allow-Originи соседние в ответе, плюс preflight-запросOPTIONS; - безопасность:
Strict-Transport-Security,Content-Security-Policy,X-Content-Type-Options: nosniff; - инфраструктура:
traceparentилиX-Request-IDдля сквозной трассировки,X-Forwarded-Forза прокси,Retry-Afterпри429и503,Locationпри редиректе и201.
Про Go. http.Header это map[string][]string, а методы Set, Get, Add приводят ключ к каноническому виду (content-type превращается в Content-Type). В хендлере заголовки ответа выставляют через w.Header().Set(...) строго до w.WriteHeader или первого w.Write: после этого они уже ушли клиенту, и изменения молча игнорируются. Если Content-Type не задан, net/http угадает его по первым байтам тела, поэтому для JSON его лучше указывать явно. Общие заголовки удобно ставить в middleware, оборачивающем http.Handler.
Где спотыкаются
Выставляют заголовок после w.Write или WriteHeader и не понимают, почему клиент его не видит.
Обращаются к r.Header["content-type"] напрямую как к map. Ключи там канонические, и такой поиск вернёт пустоту, в отличие от r.Header.Get.
Доверяют X-Forwarded-For от клиента как настоящему IP. Этот заголовок легко подделать, верить можно только значению, которое добавил ваш собственный прокси.