Transfer-Encoding: gzip vs. Content-Encoding: gzip

102

Jaki jest obecny stan rzeczy, jeśli chodzi o podjęcie decyzji

Transfer-Encoding: gzip

lub a

Content-Encoding: gzip

kiedy chcę pozwolić klientom z np. ograniczoną przepustowością na zasygnalizowanie swojej chęci przyjęcia skompresowanej odpowiedzi a serwer ma ostateczną decyzję, czy kompresować czy nie .

To ostatnie jest tym, co robią np. Mod_deflate Apache i IIS, jeśli pozwolisz mu zająć się kompresją. W zależności od rozmiaru zawartości do skompresowania, zrobi to dodatkowe Transfer-Encoding: chunked.

Będzie również zawierać Vary: Accept-Encodingpodpowiedź, która już wskazuje na problem. Content-Encodingwydaje się być częścią jednostki, więc zmianaContent-Encoding kwot w celu zmiany jednostki, tj. inny Accept-Encodingnagłówek oznacza, że ​​np. pamięć podręczna nie może używać swojej buforowanej wersji identycznej jednostki.

Czy jest jakaś konkretna odpowiedź na to pytanie, którą przegapiłem (i nie jest ona ukryta w wiadomości w długim wątku w jakiejś grupie dyskusyjnej apache)?

Moje obecne wrażenie to:

  • Transfer-Encoding byłby w rzeczywistości właściwym sposobem na zrobienie tego, co jest najczęściej robione z Content-Encoding przez istniejące implikacje serwera i klienta
  • Content-Encoding, ze względu na swoje implikacje semantyczne, niesie ze sobą kilka problemów (co powinien zrobić serwer, ETaggdy w przejrzysty sposób kompresuje odpowiedź?)
  • Powód jest taki, że chicken'n'egg: przeglądarki tego nie obsługują, ponieważ serwery nie obsługują, ponieważ przeglądarki nie obsługują

Zakładam więc, że właściwą drogą będzie Transfer-Encoding: gzip(lub, jeśli dodatkowo rozbiję ciało, stanie się Transfer-Encoding: gzip, chunked ). I nie ma powodu, by dotykać VarylubETag żadnego innego nagłówka w tym przypadku, ponieważ jest to rzecz na poziomie transportu.

Na razie nie obchodzi mnie zbytnio „przeskok po skoku” Transfer-Encoding, coś, czym inni wydają się być zainteresowani przede wszystkim, ponieważ serwery proxy mogą zdekompresować i przekazać klientowi bez kompresji. Jednak serwery proxy mogą równie dobrze przekazywać je w stanie, w jakim są (skompresowane), jeśli oryginalne żądanie ma odpowiedni Accept-Encodingnagłówek, który w przypadku wszystkich przeglądarek, które znam, jest dany.

Przy okazji, ten problem ma co najmniej dekadę, patrz np . Https://bugzilla.mozilla.org/show_bug.cgi?id=68517 .

Wszelkie wyjaśnienia w tej sprawie będą mile widziane. Zarówno pod względem tego, co jest uważane za zgodne z normami, jak i tego, co jest uważane za praktyczne. Na przykład biblioteki klienta HTTP obsługujące tylko przezroczyste „kodowanie zawartości” byłyby argumentem przeciwko praktyczności.

Eugene Beresovksy
źródło
2
Związane z: stackapps.com/questions/916/ ...
Jo Liss
Właśnie wpadłem na to. Curl w PHP 5.3 nie rozumie Transfer-Encoding:gzip, chociaż curl z linii poleceń tak. Aby być po bezpiecznej stronie, wyślij oba, chyba że łączysz fragmenty i gzip.
Seva Alekseyev
1
@SevaAlekseyev wysyłania zarówno byłoby bardzo źle - klienci mogą spróbować rozpakować dwukrotnie
Joshua Wise
To jest coś, co mnie niepokoi na zawsze ( pytanie, które zadałem )… zgodnie z jedną z odpowiedzi na pytanie, które przytoczył @JoLiss, istnieje doskonale logiczny, spójny semantycznie i zgodny ze standardami sposób kompresji treści żądania / odpowiedzi… i zasadniczo żaden klient / serwer go nie używa ani nie obsługuje. 🤦🏻‍
Dan Lenski

Odpowiedzi:

35

Cytując Roya T. Fieldinga , jednego z autorów RFC 2616:

zmiana kodowania treści w locie w niespójny sposób (ani „nigdy”, ani „zawsze) uniemożliwia poprawną obsługę późniejszych żądań dotyczących tej treści (np. PUT lub warunkowy GET). kodowanie treści w locie jest głupim pomysłem i dlaczego dodałem Transfer-Encoding do HTTP jako właściwy sposób kodowania w locie bez zmiany zasobu.

Źródło: https://issues.apache.org/bugzilla/show_bug.cgi?id=39727#c31

Innymi słowy: nie rób kodowania zawartości w locie , zamiast tego użyj Transfer-Encoding!

Edycja: to znaczy, chyba że chcesz udostępniać zawartość spakowaną gzip klientom, którzy rozumieją tylko kodowanie zawartości . Co niestety wydaje się być większością z nich. Ale pamiętaj, że opuścisz dziedzinę specyfikacji i możesz napotkać problemy takie jak ten, o którym wspomniał Fielding, a także inne, np. Gdy w grę wchodzą serwery proxy buforujące.

Evgeniy Berezovsky
źródło
3
Więc jeśli dobrze rozumiem: 1. Kodowanie treści odnosi się do kodowania treści na serwerze w sposób abstrakcyjny, tj. Treść będzie konsekwentnie serwowana w określonym kodowaniu przez serwer. 2. Kodowanie transferu odnosi się do kodowania, które serwer zdecydował się użyć do dostarczenia go agentowi użytkownika w tym przypadku, tj. W tej odpowiedzi. Tylko upewniam się, że nie zinterpretuję źle Twojej odpowiedzi.
dot slash hack
31
@KemHeyndels O właściwej. Innymi słowy: Zgodnie ze specyfikacją, Transfer-Encoding jest czysta warstwa transportowa szczegół , czyli pośredni proxy jest wolny, aby cofnąć np gzip kompresja na tym poziomie, natomiast Content-Encoding jest warstwa biznesu nieruchomość , której pełnomocnik nie będzie może się zmieniać, oprócz innych konsekwencji (znaczniki ET itp.). Jednak zgodnie z rzeczywistością , TE nie jest zwykle używane do kompresji, a wiele serwerów / klientów nie obsługuje go nawet po wyjęciu z pudełka, podczas gdy CE jest używane mniej więcej tak, jak zamierzano używać TE : jako szczegół warstwy transportowej .
Evgeniy Berezovsky
1
Więc rzeczywistość zobowiązuje nas do zignorowania rady Roya T. Fieldinga?
dot slash hack
11
@KemHeyndels Idealizm zobowiązuje Cię do dodania obsługi TE do wszystkich implementacji klienta / serwera HTTP typu open source. Następnie zatrudnij się w każdej firmie, która ma implementacje HTTP o zamkniętym kodzie źródłowym (myślę, że to tylko Microsoft) i dodaj tam również tę funkcję. Potem rzeczywistość i specyfikacja zbiegną się. ;) (A protokół HTTP 2.0 zostanie wydany, przez co problem i tak zniknie)
Evgeniy Berezovsky
10
Wskazanie, że obsługujesz Transfer-Encoding, nadal nie oznacza, że ​​obsługujesz gzip zamiast Transfer-Encoding, więc nic ci to nie daje. Wskazanie odbywa się w drugą stronę : każdy klient, który może wykonać gzip przez Transfer-Encoding, powiadomi serwer o tym, ustawiając TE: gzip. Następnie twój serwer powinien przejść na trasę Transfer-Encoding. Jeśli klient tylko mówi Accept-Encoding: gzip, musisz to zrobić po Content-Encodingdrodze. Jeśli klient nie określi żadnego w swoim żądaniu, serwer nie może w ogóle gzipować.
Evgeniy Berezovsky
28

Prawidłowe wykorzystanie, zgodnie z definicją zawartą w dokumencie RFC 2616 i faktycznie realizowane w środowisku naturalnym, jest dla klienta, aby wysłaćAccept-Encoding nagłówka żądania (klient może określić wiele kodowań). Serwer może wtedy i tylko wtedy zakodować odpowiedź zgodnie z obsługiwanymi przez klienta kodowaniami (jeśli dane pliku nie są już zapisane w tym kodowaniu), wskazać w Content-Encodingnagłówku odpowiedzi, które kodowanie jest używane. Klient może następnie odczytać dane z gniazda na podstawie Transfer-Encoding(tj. chunked), A następnie zdekodować je na podstawie Content-Encoding(tj:gzip .

Tak więc w twoim przypadku klient wyśle Accept-Encoding: gzipnagłówek żądania, a następnie serwer może zdecydować o skompresowaniu (jeśli nie jeszcze) i wysłaniu Content-Encoding: gzipi opcjonalnieTransfer-Encoding: chunked nagłówka odpowiedzi.

I tak, plik Transfer-Encoding nagłówek może być używany w żądaniach, ale tylko w przypadku protokołu HTTP 1.1, który wymaga, aby implementacje klienta i serwera obsługiwały chunkedkodowanie w obu kierunkach.

ETagjednoznacznie identyfikuje dane zasobów na serwerze, a nie dane faktycznie przesyłane. Jeśli dany zasób adresu URL zmienia swoją ETagwartość, oznacza to, że zmieniły się dane po stronie serwera dla tego zasobu.

Remy Lebeau
źródło
14
kodowanie treści jest cechą jednostki identyfikowanej przez Request-URI Innymi słowy: Różne Content-Encodingwymagania różneETag To właśnie dotyczy błędu mod_deflate, o którym mówię w mojej odpowiedzi. Zastanawiam się, dlaczego te szczegóły na poziomie aplikacji są w standardzie HTTP. Transfer-EncodingJednak podczas korzystania z ustawienia poziomu transportu nie ma potrzeby zmiany pliku ETag. Poza tym, że nikt nie zaimplementował Transfer-Enc.
Evgeniy Berezovsky
2
Kodowanie zawartości nie jest przeznaczone do kodowania „w locie”. RFC 2616 mówi, że „Transfer-Encoding ... różni się od kodowania treści tym, że kodowanie transferu jest właściwością wiadomości, a nie jednostki”. ( Tools.ietf.org/html/rfc2616#section-14.41 ) oraz „Kodowanie treści jest charakterystyką jednostki identyfikowanej przez identyfikator URI żądania. Zwykle treść jednostki jest przechowywana z tym kodowaniem” ( tools.ietf.org/html/rfc2616#section-14.11 ). Więc głosuję przeciw.
Robert
Co opisałem to, co jest „ rzeczywiście realizowane na dziko ”, bez względu Content-Encodingvs Transfer-Encoding. Tak, gzip powinien być właściwością transferu zasobu, jeśli odbywa się w locie. Z drugiej strony, jeśli zasób jest przechowywany w postaci skompresowanej na serwerze, powinien być zamiast tego właściwością zawartości zasobu, jeśli jest wysyłany w stanie, w jakim jest. Ale to, co powinno być, a co faktycznie jest, nie zawsze jest tym samym.
Remy Lebeau