NginxはチャンクコンテンツのContent-Lengthヘッダーを削除します


10

nginx 1.2.3を使用してスクリプトにプロキシします。

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

スクリプトはTransfer-encoding: chunkedとの両方を送信しますContent-Length: 251

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

私は両方が必要ですが、nginxは自動的に削除し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: /...

その結果、クライアントはチャンクが送信されるのを待ちません。これは以前のバージョンのnginxで機能していました。


nginxプロキシのヘッダーはどのように見えますか?
2013

以前使用していたバージョンはどれですか?
cnst 2013年

以前はnginx 0.9.8で動作していました
Julien

HTTPプロトコルに違反しています。1.1.4バージョンまでチャンクエンコーディングをまったくサポートしていないため、nginx 0.9.8で動作します。
VBart 2013

回答:


11

残念ながら、cnstの投稿にはコメントできません。ここで回答します。

nginx_http_proxyHTTP / 1.0の上流でデフォルトの会談によってモジュール。これはディレクティブで変更できますproxy_http_version 1.1

これもスクリプトがHTTP / 1.0応答を返す原因となる可能性がありますが、チャンクコーディングとステータスコード307はこのバージョンには存在しません。

リダイレクトではチャンクコーディングも使用しないでください。これは実際には意味がありません。

さらに、nginx 上流からクライアントにチャンクを1つずつ渡さないようですが、上流の応答をバッファリングします。Content-Lengthそれは定義に反しているので、ヘッダフィールドは無視されます。ドキュメント化されていないように見えるため、モジュールのソースコードを確認する必要がありました。

あなたは試してみたいことnginx_tcp_proxy_module:生のTCPデータとしてプロキシにチャンクコンテンツモジュールのGithubでの


UPDATE(10.04.14)モジュールのための支持有するヘッダーの一方(、応答がバッファリングするかどうか)を制御します。
nginx_http_proxyX-Accel-* X-Accel-Buffering: yes|no

このヘッダー(X-Accel-Buffering: no)をバックエンドの応答に追加すると、nginxはチャンクをクライアントに直接渡します。

このヘッダーにより、リクエストごとにバッファリングを制御できます

モジュールには、応答のバッファリングを有効または無効にする構成ディレクティブ もありますproxy_buffering(バッファリングしないと、チャンクの送信が機能します)。

プロキシバッファリング(ヘッダーとディレクティブの両方に基づく)は、ここに記載されています


彼はそれをしてはいけませんnginx_tcp_proxy_module。非常にエラーに強いため、一部のブラウザでのみ機能します。
VBart 2013

これはすべて文書化されていないようです。これは、RFC 2616を参照してくださいに記載されます13.5.1
VBart 2013

@VBart確かに標準はありますが、特にnginxが標準をどれだけ実装しているかについての情報はほとんどありません。TCPプロキシモジュールは推奨される回避策です。
Lukas

9

Lukasが示唆しているように、HTTP 1.1 Content-LengthTransfer-Encodingセットがあると禁止します。

引用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.

さらに、HTTP 1.1に準拠したNginxの正しい動作は、HTTPリクエストの密輸攻撃を防ぐのに大いに役立ちます
午前

3

特にリダイレクト応答で、スクリプトが最初にチャンクエンコーディングを必要とする理由を具体的に詳しく説明していません。

ここには多くの問題があります。

  • Transfer-Encoding: chunkedあるHTTP/1.1機能は、(とあなたのスクリプトがで応答しているようだHTTP/1.0ヘッダ)

  • 何もありません307では、HTTP/1.0

  • の全体的な目的chunkedは、自分が何であったかわからないことですContent-Length。そのため、chunkedContent-Lengthで長さを提供する代わりに使用されます。代わりに、長さが実際のコンテンツと混合された応答の本文内で提供されます。スクリプトが両方のヘッダーを前もって生成することは無意味です

私は個人的には詳しくありませんchunkedが、http://en.wikipedia.org/wiki/Chunked_transfer_encodingおよびhttp://tools.ietf.org/html/rfc2616#section-3.6.1の基本情報に従って、チャンクされたエンコードのスクリプト全体の処理が完全に間違っている可能性があると思います。

上記がまだそれをカバーしていない場合、そして実際にはそれ以外の場合は、307または302httpステータスコードを含む応答が「奇妙な」エンコーディングで提供される理由も不明です。最近、nginxメーリングリストで同様の議論があり410 Gone、その他のエラーページは常にgzip圧縮から除外されていました。(http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html


ユーザーを待機させるためにそれを使用します。チャンクを毎秒送信するので、ユーザーはタイムアウトを取得せずにリダイレクトをX秒間待機します
Julien

私は(これらのものは/ 1.0 HTTP / 1.1への最初の修正HTTPにあなたをお勧めする違いを作る)、そして、あなたのチャンクエンコーディングが不適切ではないことを確認してください。nginxの新しいバージョンでは、間違っているために依存しているヘッダーが破棄される可能性があります。
cnst 2013年

1

同じ問題がhtml5ビデオタグを介してmp4ファイルをストリーミングしていました。

SafariとFirefoxは正常に動作しましたが、Chromeはある時点でERR_CONTENT_LENGTH_MISMATCHをトリガーしていました(ただし、失敗する前に数分間ビデオを見ることができました)。

mp4ファイルのキャッシュ制御をオフにした後、問題は再現しませんでした。


0

役に立った場合に備えて私がSOに投稿したこの回答を共有する:https : //stackoverflow.com/questions/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

チャンクが提供されていないためにmp4再生で同様の問題があり、以下にリストされているAppleのガイドに従って問題を確認しました。ファイル全体をダウンロードしていることを確認し、以下の修正後、最初のチャンクのみを確認しました。

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

.mp4ファイルのgzip圧縮を削除するために、nginx.confのgzip圧縮設定を変更して、Safari .mp4再生を解決しました。

参考のために、nginxのブロックを以下に示します。(注:アプリの構成方法によっては、ロケーションラインをlocation ~ \.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;
}

Appleドキュメントリファレンスへのリンク:https : //developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/TP40006514-SW6

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.