Автоматическое сжатие на клиенте vs ручное на сервере
Стандартный клиент
http.Transport сам добавляет в запрос
Accept-Encoding: gzip и, если сервер отвечает с
Content-Encoding: gzip, клиент сам распакует ответ. Но только пока
Accept-Encoding не выставлен вручную. Если клиент сам задаёт этот заголовок (случайно либо намеренно с указанием другого алгоритма типа `zstd`) логику распаковки тоже надо писать самому. Подробнее прямо описано в
доке `net/http`
Интересно, что на сервере симметричной автоматики нет.
http.Server сам ответы не сжимает - и это довольно логично: но стороне сервера eщё нужно решить, стоит ли вообще сжимать конкретный ответ. Все таки сжатие переносит часть стоимости с сети на cpu: сервер и клиент тратят проц на переупаковки в обмен на уменьшение объёма передаваемых по сети данных.
Поэтому для тех, кому экономия на сжатии превышает доп вычисления, будет полезно обернуть хендлер небольшим миддлваром, например через
https://github.com/klauspost/compress:
func responseCompressionMiddleware(next http.Handler) http.Handler {
return gzhttp.GzipHandler(next)
}
Нейминг может запутать, потому что
gzhttp.GzipHandler умеет не только
gzip, но и
zstd: алгоритм выбирается по
Accept-Encoding, а при одинаковом приоритете
q выбирает
zstd.
А если передаются секреты или другая sensitive инфа, у
gzhttp можно добавить
RandomJitter - оберточная функция, которая добавляет небольшой padding, размывая точный размер сжатого ответа, чтобы нарушитель не смог по небольшим изменениям размера косвенно угадывать части секрета
Также можно обернуть весь клиент
http.Transport через
gzhttp.Transport и автоматическая распаковка будет распространяться уже и на
zstd - тогда как стандартный
http.Transport автоматически работает только с
gzip. Не знаю, насколько это общеизвестная деталь, но я даже про
gzip под капотом узнала только сейчас :-)
#go #perf