Заголовок Content-Length по сравнению с закодированным кодированием

Я пытаюсь взвесить плюсы и минусы настройки заголовка Content-Length HTTP по сравнению с использованием закодированного кодирования, чтобы вернуть [возможно] большие файлы с моего сервера. Тот или иной необходим для соответствия спецификациям HTTP 1.1 с использованием постоянных соединений. Я вижу преимущество заголовка Content-Length:

  • Диалоги загрузки могут показывать точный индикатор выполнения.
  • Клиент знает upfront, если файл может/не быть слишком большим для того, чтобы они могли глотать

Недостатком является вычисление размера, прежде чем вы вернете объект, который не всегда практичен и может добавить к использованию сервера/базы данных. Недостатком закодированного кодирования является небольшие накладные расходы на добавление размера блока перед каждым фрагментом и индикатором выполнения загрузки. Есть предположения? Любые другие соображения HTTP для обоих методов, о которых я, возможно, и не думал?

Ответ 1

Используйте Content-Length, определенно. Использование сервера из этого будет почти несуществующим, и польза для ваших пользователей будет большой.

Для динамического контента также довольно просто добавить поддержку сжатого ответа (gzip). Для этого требуется буферизация вывода, которая, в свою очередь, дает вам длину содержимого. (не практично с загрузкой файлов или уже сжатым контентом (звук, изображения)).

Рассмотрим также добавление поддержки частичного контента/byte-range - то есть возможность перезапуска загрузки. См. здесь пример байтового диапазона (пример приведен в PHP, но применим на любом языке). Для частичного содержимого вам требуется Content-Length.

Конечно, это не серебряные пули: для потоковой передачи данных бессмысленно использовать буферизацию или размер ответа; для больших файлов буферизация вывода не имеет смысла, но обработка Content-Length и байт имеет большой смысл (возможен перезапуск неудачной загрузки).

Лично я обслуживаю Content-Length всякий раз, когда знаю это; для загрузки файлов проверка размера файла незначительна с точки зрения ресурсов. Результат: пользователь имеет определенный индикатор выполнения (и динамические страницы загружаются быстрее благодаря gzip).

Ответ 2

Если длина контента известна заранее, я бы, конечно, предпочел бы, чтобы она была выше отправки в кусках. Если есть средства статических файлов в локальной файловой системе или в базе данных, то любой уважающий себя язык программирования и СУБД предоставляет способы заранее получить длину содержимого. Вы должны использовать его.

С другой стороны, если длина контента на самом деле непредсказуема заранее (например, когда вы намерены объединить несколько файлов вместе и отправить их как один), то отправка его в куски может быть быстрее, чем буферизация в памяти сервера или запись к локальной файловой системе диска. Но это действительно отрицательно сказывается на работе пользователя, поскольку процесс загрузки неизвестен. Затем нетерпение может прекратить загрузку и двигаться вперед.

Еще одним преимуществом знания длины контента является возможность возобновления загрузки. В вашей истории сообщений я вижу, что основным языком программирования является Java; вы можете найти здесь статью с более технической справочной информацией и примером Java Servlet, который это делает.

Ответ 3

Content-Length

Заголовок Content-Length определяет длину байта тела запроса/ответа. Если вы не укажете заголовок Content-Length, HTTP-серверы неявно добавят заголовок Transfer-Encoding: chunked. Заголовки Content-Length и Transfer-Encoding не должны использоваться вместе. Получатель не будет знать, какова длина тела и не может оценить время завершения загрузки. Если вы добавляете заголовок Content-Length, убедитесь, что он соответствует всему телу в байтах, если он неверен, поведение приемников undefined.

Заголовок Content-Length не разрешает потоковую передачу, но он полезен для больших двоичных файлов, где вы хотите поддерживать частичное обслуживание контента. Это в основном означает возобновляемые загрузки, приостановленные загрузки, частичные загрузки и многопользовательские загрузки. Для этого требуется использование дополнительного заголовка с именем Range. Этот метод называется Байт, обслуживающий.

Transfer-Encoding

Использование Transfer-Encoding: chunked - это то, что позволяет передавать потоки в рамках одного запроса или ответа. Это означает, что данные передаются по-разному и не влияют на представление содержимого.

Официально клиент HTTP предназначен для отправки запроса с полем заголовка TE, который указывает, какие типы кодировок передачи, которые клиент готов принять. Это не всегда отправляется, однако большинство серверов предполагают, что клиенты могут обрабатывать кодировки chunked.

Кодирование передачи chunked позволяет лучше использовать постоянные TCP-соединения, которые по умолчанию HTTP 1.1 принимает значение true.

Content-Encoding

Также возможно сжимать отдельные или необработанные данные. Это делается практически через заголовок Content-Encoding.

Обратите внимание, что Content-Length равно длине тела после Content-Encoding. Это означает, что если у вас есть gzipped ваш ответ, то вычисление длины происходит после сжатия. Вам нужно будет иметь возможность загружать все тело в память, если вы хотите вычислить длину (если у вас нет этой информации в другом месте).

При потоковой передаче с использованием закодированного кодирования алгоритм сжатия также должен поддерживать онлайн-обработку. К счастью, gzip поддерживает сжатие потока. Я считаю, что контент сначала сжимается, а затем разрезается на куски. Таким образом, куски принимаются, затем распаковываются, чтобы получить реальный контент. Если бы это было наоборот, вы получите сжатый поток, а затем распаковка даст нам куски. Это не имеет смысла.

Типичный сжатый поток может иметь следующие заголовки:

Content-Type: text/html
Content-Encoding: gzip
Transfer-Encoding: chunked

Семантически использование Content-Encoding указывает схему кодирования "от конца до конца", что означает, что только конечный клиент или конечный сервер должен декодировать контент. Прокси в середине не допускают декодирования содержимого.

Если вы хотите разрешить прокси-серверам посередине декодировать контент, правильным заголовком является фактический заголовок Transfer-Encoding. Если HTTP-запрос обладал заголовком TE: gzip chunked, тогда можно ответить с помощью Transfer-Encoding: gzip chunked.

Однако это очень редко поддерживается. Поэтому вы должны использовать Content-Encoding для вашего сжатия прямо сейчас.

Chunked vs Store and Forward