Заголовок 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