Короткий ответ
Content-Length сообщает получателю точный размер тела сообщения в байтах, чтобы он знал, когда тело полностью получено; если значение указано неверно (меньше или больше фактического размера), получатель может обрезать данные или зависнуть, ожидая оставшиеся байты.
Как это работает подробнее
при использовании keep-alive заголовок Content-Length критичен, чтобы сервер/клиент понимал, где заканчивается текущий ответ и начинается следующий в рамках одного TCP-соединения; альтернатива — Transfer-Encoding: chunked, когда размер неизвестен заранее (например, при потоковой передаче).
Пример кода
example.py
# Намеренная ошибка: длина считается по символам, а не по байтам UTF-8
text = "Привет" # 6 символов, но 12 байт в UTF-8
wrong_length = len(text) # 6 — неверно для Content-Length
correct_length = len(text.encode("utf-8")) # 12 — корректноЧто использовать на практике
- Рекомендация. в большинстве backend-фреймворков этот заголовок выставляется автоматически на основе фактического тела ответа, и разработчику не нужно считать его руками. Вручную считать длину нужно, если тело собирается в несколько этапов или идёт стриминг с явным указанием размера.
Подводные камни
- Риски. вручную выставлять Content-Length при прокси/модификации тела ответа (например, в middleware, которое меняет текст), забывая пересчитать длину после изменения — это приводит к обрезанному или "зависшему" ответу на стороне клиента; путать Content-Length с количеством символов в строке без учёта многобайтовой кодировки UTF-8 для не-ASCII текста.