Nginx entfernt den Content-Length-Header für Chunked-Inhalte

10

Ich verwende Nginx 1.2.3 als Proxy für ein Skript:

proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8880;
proxy_buffering off;
proxy_read_timeout 300s;
gzip off;

Die Skripte senden beide Transfer-encoding: chunkedund Content-Length: 251:

HTTP/1.0 307 Temporary Redirect
Content-length: 251
Pragma: no-cache
Location: /...
Cache-control: no-cache
Transfer-encoding: chunked

Ich brauche beides, aber nginx entfernt automatisch das Content-Length:

HTTP/1.1 302 Found
Server: nginx/1.2.3
Content-Type: application/json; charset=utf-8
Content-Length: 58
Connection: keep-alive
Location: /...

Infolgedessen warten die Clients nicht auf das Senden der Chunks. Dies funktionierte früher mit einer früheren Version von Nginx.

Julien
quelle
Wie sehen die Header vom Nginx-Proxy aus?
Jagd
Mit welcher Version hat es früher funktioniert?
cnst
Es funktionierte mit Nginx 0.9.8
Julien
Sie verletzen das HTTP-Protokoll. Es funktioniert mit Nginx 0.9.8, da es bis zur Version 1.1.4 überhaupt keine Chunked-Codierung unterstützt.
VBart

Antworten:

11

Leider kann ich den Beitrag von cnst nicht kommentieren - daher werde ich hier antworten.

Das nginx_http_proxyModul kommuniziert standardmäßig mit dem Upstream in HTTP / 1.0. Dies kann mit der Richtlinie geändert werden proxy_http_version 1.1.

Dies kann auch die Ursache dafür sein, dass Ihr Skript eine HTTP / 1.0-Antwort zurückgibt, obwohl Chunked Coding und Statuscode 307in dieser Version nicht vorhanden sind.

Sie sollten auch keine Blockcodierung mit einer Umleitung verwenden , da dies nicht wirklich sinnvoll ist.

Darüber hinaus scheint es so, als ob Nginx keine Chunks vom Upstream einzeln an den Client weiterleitet, sondern die Antwort des Upstreams puffert . Das Content-LengthHeader-Feld wird ignoriert, da es gegen die Definition verstößt. Ich musste mir den Quellcode des Moduls ansehen, da dies alles undokumentiert zu sein scheint.

Möglicherweise möchten Sie versuchen, den nginx_tcp_proxy_moduleChunk-Inhalt als TCP-Rohdaten zu vertreten: Modul bei Github


UPDATE (10.04.14)
Das nginx_http_proxyModul unterstützt X-Accel-* Header , von denen one ( X-Accel-Buffering: yes|no) steuert, ob die Antwort gepuffert werden soll oder nicht.

Wenn Sie diesen Header ( X-Accel-Buffering: no) zur Antwort des Backends hinzufügen, übergibt nginx Chunks direkt an den Client.

Dieser Header ermöglicht die Steuerung der Pufferung pro Anforderung .

Das Modul verfügt außerdem über eine Konfigurationsanweisung proxy_buffering zum Aktivieren oder Deaktivieren der Antwortpufferung (keine Pufferung bedeutet, dass das Senden von Chunks funktioniert).

Die Proxy-Pufferung (sowohl auf Header- als auch auf Direktivenbasis) ist hier dokumentiert .

Lukas
quelle
Er sollte das nicht einmal mit tun nginx_tcp_proxy_module. Es funktioniert nur mit einigen Browsern, weil sie sehr fehlertolerant sind.
VBart
weil all dies undokumentiert zu sein scheint Falsch. Es ist in RFC 2616 dokumentiert . Siehe 13.5.1 .
VBart
@VBart Sicher gibt es Standards - aber es gibt nur sehr wenige Informationen darüber , wie weit besonders nginx implementiert haben.Die TCP - Proxy - Modul ist hust eine vorgeschlagene Abhilfe .
Lukas
9

Wie Lukas anspielt, verbietet HTTP 1.1, Content-Lengthwenn es einen Transfer-EncodingSatz gibt.

Zitat http://www.ietf.org/rfc/rfc2616.txt :

   3.If a Content-Length header field (section 14.13) is present, its
     decimal value in OCTETs represents both the entity-length and the
     transfer-length. The Content-Length header field MUST NOT be sent
     if these two lengths are different (i.e., if a Transfer-Encoding
     header field is present). If a message is received with both a
     Transfer-Encoding header field and a Content-Length header field,
     the latter MUST be ignored.
Jo Liss
quelle
Darüber hinaus trägt das korrekte Verhalten von Nginx in Übereinstimmung mit HTTP 1.1 wesentlich dazu bei, Angriffe auf den Schmuggel von HTTP-Anforderungen zu verhindern .
amn
3

Sie haben nicht speziell erläutert, warum Ihr Skript überhaupt eine Chunk-Codierung benötigt, insbesondere mit einer Umleitungsantwort.

Ich sehe hier eine Vielzahl von Problemen.

  • Transfer-Encoding: chunkedist eine HTTP/1.1Funktion (und Ihr Skript scheint mit einem HTTP/1.0Header zu antworten )

  • es gibt kein 307inHTTP/1.0

  • Der ganze Zweck von chunkedist, dass Sie nicht wissen, was Ihre gewesen Content-Lengthwäre, also chunkedwird anstelle der Angabe der Länge innerhalb verwendet Content-Length, wobei stattdessen Längen innerhalb des Hauptteils der Antwort angegeben werden, vermischt mit dem tatsächlichen Inhalt; Es wäre sinnlos, wenn ein Skript beide Header im Voraus generieren würde

Ich bin nicht persönlich vertraut chunked, aber gemäß den grundlegenden Informationen unter http://en.wikipedia.org/wiki/Chunked_transfer_encoding und auch http://tools.ietf.org/html/rfc2616#section-3.6.1 , Ich würde schätzen, dass die gesamte Handhabung der Chunk-Codierung durch Ihr Skript möglicherweise völlig falsch ist.

Wenn das oben Gesagte es immer noch nicht abdeckt, und in Wirklichkeit auch sonst, ist es auch unklar, warum eine Antwort mit einem 307oder 302http-Statuscode mit einer "seltsamen" Codierung versehen werden sollte. Es gab kürzlich eine ähnliche Diskussion in der Nginx-Mailingliste über 410 Goneund andere Fehlerseiten, die immer von der gzipKomprimierung ausgeschlossen waren , und ich denke, das Gefühl würde hier gleichermaßen gelten. ( http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html )

cnst
quelle
Ich benutze es, um den Benutzer warten zu lassen: Ich sende alle Sekunden Chunks, damit der Benutzer X Sekunden auf die Umleitung wartet, ohne eine Zeitüberschreitung zu bekommen
Julien
Ich würde Sie zum ersten Fix HTTP / 1.0 HTTP / 1.1 beraten (diese Dinge tun , einen Unterschied machen), und stellen Sie sicher , dass Ihre aufgeteilte Codierung ist nicht unpassend. Die neuere Version von nginx verwirft wahrscheinlich einige Header, von denen Sie abhängig sind, weil sie falsch sind.
cnst
1

Ich hatte das gleiche Problem beim Streamen von MP4-Dateien über HTML5-Video-Tags.

Safari und Firefox verhielten sich normal, während Chrome irgendwann ERR_CONTENT_LENGTH_MISMATCH auslöste (aber es erlaubte mir, einige Minuten des Videos zu sehen, bevor es fehlschlug).

Das Problem wurde nicht reproduziert, nachdem ich die Cache-Steuerung für MP4-Dateien deaktiviert hatte.

Buzut
quelle
0

Diese Antwort habe ich an SO gesendet, falls sie hilfreich ist: /programming/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

Ich hatte ein ähnliches Problem mit der MP4-Wiedergabe, da Chunks nicht bereitgestellt wurden, und bestätigte das Problem gemäß dem unten aufgeführten Apple-Handbuch. Ich habe überprüft, ob ich die gesamte Datei heruntergeladen habe, und nach dem folgenden Fix nur den ersten Block.

curl --range 0-99 http://example.com/test.mov -o /dev/null

Ich habe meine Safari .mp4-Wiedergabe aufgelöst, indem ich meine Einstellungen für die gzip-Komprimierung in meiner nginx.conf geändert habe, um die gzip-Komprimierung von .mp4- Dateien zu entfernen .

Hier ist der Block in Nginx als Referenz. (Hinweis: Je nachdem, wie Ihre App konfiguriert ist, müssen Sie möglicherweise die Standortzeile in ändernlocation ~ \.mp4$ {

location ~ ^/(assets|system|videos)/  {
   expires max;
   add_header Cache-Control public;
   add_header ETag "";
   gzip on;
   gzip_http_version 1.1;
   gzip_vary on;
   gzip_comp_level 6;
   gzip_proxied any;

   # Reference configuration
   #gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript video/mp4 application/mp4 image/jpeg image/png image/svg+xml application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;

   # Kelton trying to fix cloudflare by removing the mp4 settings
   gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript image/jpeg image/png image/svg+xml application/application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;
}

Link zur Apple-Dokumentationsreferenz: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/

Kelton.Temby
quelle