Кодирование передачи: gzip против кодирования содержимого: gzip

100

Каково текущее положение дел, когда дело доходит до того, нужно ли делать

Transfer-Encoding: gzip

или

Content-Encoding: gzip

когда я хочу разрешить клиентам, например, с ограниченной пропускной способностью, сигнализировать о своей готовности принять сжатый ответ, и последнее слово остается за сервером, сжимать или нет .

Последнее - то, что делают, например, Apache mod_deflate и IIS, если вы позволите ему позаботиться о сжатии. В зависимости от размера сжимаемого содержимого он будет выполнять дополнительные функции Transfer-Encoding: chunked.

Он также будет включать в себя Vary: Accept-Encoding, который уже намекает на проблему. Content-Encodingкажется, является частью объекта, поэтому изменение Content-Encodingсумм означает изменение объекта, то есть другой Accept-Encodingзаголовок означает, например, что кеш не может использовать свою кэшированную версию идентичного объекта.

Есть ли определенный ответ на этот вопрос, который я пропустил (и который не похоронен внутри сообщения в длинной цепочке какой-нибудь группы новостей apache)?

Мое текущее впечатление:

  • Transfer-Encoding на самом деле будет правильным способом сделать то, что в основном делается с Content-Encoding существующими серверными и клиентскими реализациями.
  • Content-Encoding из-за своего семантического значения несет в себе несколько проблем (что должен делать сервер, ETagкогда он прозрачно сжимает ответ?)
  • Причина в том, что это курица и яйцо: браузеры не поддерживают ее, потому что серверы не поддерживают ее, потому что браузеры не поддерживают ее.

Итак, я предполагаю, что правильным способом будет Transfer-Encoding: gzip(или, если я дополнительно разделю тело, оно станет Transfer-Encoding: gzip, chunked ). И нет причин трогать Varyили ETagили любой другой заголовок в этом случае, поскольку это вещь транспортного уровня.

На данный момент меня не слишком заботит "переход за шагом" Transfer-Encoding, то, что, кажется, беспокоит других в первую очередь, потому что прокси-серверы могут распаковывать и пересылать несжатые данные клиенту. Однако прокси-серверы могут пересылать его как есть (сжатый), если исходный запрос имеет правильный Accept-Encodingзаголовок, что для всех известных мне браузеров является заданным.

Кстати, этой проблеме как минимум десять лет, см., Например, https://bugzilla.mozilla.org/show_bug.cgi?id=68517 .

Мы будем благодарны за любые разъяснения по этому поводу. И с точки зрения того, что считается соответствующим стандартам, и с точки зрения практичности. Например, клиентские библиотеки HTTP, поддерживающие только прозрачное «Content-Encoding», будут аргументом против практичности.

Евгений Бересовский
источник
2
Связано: stackapps.com/questions/916/…
Джо Лисс
Просто столкнулся с этим. Curl в PHP 5.3 не понимает Transfer-Encoding:gzip, хотя curl из командной строки понимает . На всякий случай отправьте оба, если вы не объединяете chunked и gzip.
Сева Алексеев
1
@SevaAlekseyev отправить оба было бы очень неправильно - клиенты могут попытаться распаковать дважды
Джошуа Уайз
Это то, что меня тоже всегда беспокоило ( вопрос, который я задал ) ... согласно одному из ответов на вопрос, процитированный @JoLiss, существует совершенно логичный, семантически последовательный и соответствующий стандартам способ сжатия тел запросов / ответов ... и в основном никакие клиенты / серверы не используют и не поддерживают его. 🤦🏻‍
Дэн Ленски

Ответы:

35

Цитата Роя Т. Филдинга , одного из авторов RFC 2616:

изменение кодирования содержимого "на лету" непоследовательным образом (ни "никогда", ни "всегда") делает невозможным правильную обработку последующих запросов, касающихся этого содержимого (например, PUT или условного GET). Конечно, именно поэтому выполнение Кодирование содержимого на лету - глупая идея, и почему я добавил Transfer-Encoding в HTTP как правильный способ выполнять кодирование на лету без изменения ресурса.

Источник: https://issues.apache.org/bugzilla/show_bug.cgi?id=39727#c31

Другими словами: не выполняйте кодирование содержимого на лету , используйте вместо этого Transfer-Encoding!

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

Евгений Березовский
источник
3
Итак, если я правильно понял: 1. Кодирование содержимого относится к кодированию содержимого на сервере в абстрактном виде, т.е. содержимое будет последовательно обслуживаться сервером в указанной кодировке. 2. Передача-кодирование относится к кодировке, которую сервер решил использовать для доставки его пользовательскому агенту в этом случае, то есть в этом ответе. Просто убедитесь, что я правильно истолковал ваш ответ.
dot Slash hack
30
@KemHeyndels Правильно. Другими словами: согласно спецификациям, Transfer-Encoding - это чистая деталь транспортного уровня , то есть промежуточный прокси-сервер может отменить, например, сжатие gzip на этом уровне, тогда как Content-Encoding - это свойство бизнес-уровня , которое прокси-сервер не будет разрешено изменять в дополнение к другим разветвлениям (ETags и т. д.). Однако в реальности TE обычно не используется для сжатия, и многие серверы / клиенты даже не поддерживают его из коробки, тогда как CE используется более или менее так, как предполагалось использовать TE : в качестве детали транспортного уровня. .
Евгений Березовский
1
Значит, действительность заставляет нас игнорировать совет Роя Т. Филдинга?
dot slash hack
11
@KemHeyndels В соответствии с идеализмом вы должны сначала добавить поддержку TE во все реализации HTTP-клиент / сервер с открытым исходным кодом. Затем найдите себе работу в каждой компании, у которой есть реализации HTTP с закрытым исходным кодом (я думаю, что это только Microsoft), и добавьте туда эту функцию. После этого реальность и спецификация совпадут. ;) (И HTTP 2.0 будет выпущен, и проблема все равно исчезнет)
Евгений Березовский
10
Указание, что вы поддерживаете Transfer-Encoding, по-прежнему не означает, что вы поддерживаете gzip вместо Transfer-Encoding, так что это вам ничего не даст. Индикация выполняется наоборот : любой клиент, который может выполнять gzip через Transfer-Encoding, сообщит серверу настройкой TE: gzip. И тогда ваш сервер должен пойти по маршруту Transfer-Encoding. Если клиент только говорит Accept-Encoding: gzip, вы должны делать это как надо Content-Encoding. Если клиент не указывает ни то, ни другое в своем запросе, сервер вообще не должен использовать gzip.
Евгений Березовский
28

Правильное использование, как это определено в RFC 2616 и фактически реализованы в дикой природе, для клиента , чтобы послать Accept-Encodingзаголовок запроса (клиент может указать несколько кодировок). Затем сервер может и только тогда закодировать ответ в соответствии с кодировками, поддерживаемыми клиентом (если данные файла еще не сохранены в этой кодировке), указать в Content-Encodingзаголовке ответа, какая кодировка используется. Затем клиент может считывать данные из сокета на основе Transfer-Encoding(т. Е. chunked), А затем декодировать их на основе Content-Encoding(т. Е. gzip).

Итак, в вашем случае клиент отправит Accept-Encoding: gzipзаголовок запроса, а затем сервер может решить сжать (если еще не) и отправить Content-Encoding: gzipи, возможно, Transfer-Encoding: chunkedзаголовок ответа.

И да, Transfer-Encodingзаголовок можно использовать в запросах, но только для HTTP 1.1, который требует, чтобы реализации как клиента, так и сервера поддерживали chunkedкодирование в обоих направлениях.

ETagоднозначно идентифицирует данные ресурса на сервере, а не фактически передаваемые данные. Если данный ресурс URL меняет свое ETagзначение, это означает, что данные на стороне сервера для этого ресурса изменились.

Реми Лебо
источник
14
Content-coding - это характеристика объекта, идентифицированного Request-URI. Другими словами: для другого Content-Encodingтребуется другое.ETag Это, кстати, и есть ошибка mod_deflate, о которой я упоминаю в своем ответе. Это заставляет меня задаться вопросом, почему эта детализация уровня приложения вообще находится в стандарте HTTP. Однако при использовании Transfer-Encodingнастройки транспортного уровня нет необходимости изменять ETag. Кроме того, что никто не внедрил Transfer-Enc.
Евгений Березовский
2
Content-Encoding не предназначен для кодирования «на лету». RFC 2616 гласит: «Кодирование передачи ... отличается от кодирования содержимого тем, что кодирование передачи является свойством сообщения, а не объекта» ( tools.ietf.org/html/rfc2616#section-14.41 ) и «Кодирование содержимого является характеристикой объекта, идентифицированного Request-URI. Обычно тело объекта сохраняется с этой кодировкой» ( tools.ietf.org/html/rfc2616#section-14.11 ). Поэтому я голосую против.
Роберт
То , что я описал то , что « на самом деле реализуется в дикой природе », независимо от того, Content-Encodingпротив Transfer-Encoding. Да, gzip должен быть свойством передачи ресурса, если это делается "на лету". С другой стороны, если ресурс хранится на сервере в сжатом виде, он должен быть свойством содержимого ресурса, если отправляется как есть. Но то, что должно быть, и то, что есть на самом деле , не всегда одно и то же.
Реми Лебо,