9

PHP によって動的に生成される特に大きな JSON 文字列を読み込んでいます。ユーザーにフィードバックを提供するために、ダウンロードの進行状況を表示したいと思います。

コードを理解しましたが、画像、JS ファイルなどの静的コンテンツでは問題なく動作しますが、動的ファイルでは動作しないようです。

動的ファイルには予測可能なコンテンツの長さがないため、これは理にかなっていますが、これを PHP に追加したとしても:

ob_start(function($c) {
    header("Content-Length: ".strlen($c));
    return $c;
});

それでもヘッダーは送信されません (ただし、他のヘッダーを追加すると正常に動作します)。

Apache にContent-Lengthヘッダーを強制的に送信させる方法はありますか? 現在、私の唯一の代替手段は、出力を一時ファイルに保存し、代わりにリダイレクトすることです。これは機能しますが、面倒なので、できれば避けたいと思います。

4

5 に答える 5

9

同様の問題がありましたが、私の場合、応答が gzip 圧縮されていたため、Content-Length ヘッダーが Apache から送信されませんでした。圧縮を無効にすると、Content-Length が計算され、適切に送信されました。

以下は、swf ファイルのみの gzip 圧縮を無効にする htaccess 設定です。

<FilesMatch "\.swf$">
  SetEnv no-gzip 1
</FilesMatch>
于 2014-02-18T04:24:26.823 に答える
0

ob_startドキュメントから:

This function will turn output buffering on. While output buffering is active no 
output is sent from the script (other than headers), instead the output is stored 
in an internal buffer.

「ヘッダー以外」ビットに注意してください。ob_start()コールバックは、バッファーがフラッシュされる (または破棄される) まで呼び出されません。この時点では、使用するには遅すぎますheader()。エラーログがオンになっていないと思います。エラーログに次のように表示されます。

PHP Warning:  Cannot modify header information - headers already sent 
  in /usr/local/apache2/apps/testing/test2.php on line 6

コールバックを使用すると、送信前にバッファを変更できますが、これには本文データしか含まれていないため、新しいヘッダーを追加することもできません (試してみると、チャンク転送のチャンクごとに 1 回、コンテンツに表示されます)。

header("Content-Length: ...")サイズがわかったら、他の出力の前に、代わりにコードを呼び出す必要があります。ヘッダーが見つかった場合Content-Length:、チャンク転送は行われません。

本当にHTTP/1.0 を強制する必要がある場合(必要ありません)、httpd.conf特殊変数を使用して実行できます。

SetEnv downgrade-1.0 1
SetEnv force-response-1.0 1

これらをたとえば<Location>またはに配置するか、の " " フラグを使用してより詳細に制御できます。<LocationMatch>mod_rewriteenv

于 2013-02-01T12:54:28.080 に答える
0

HTTP プロトコルには、応答がいつ終了したかを判断する方法が必要です。によると

RFC2616 セクション 4

4.4 メッセージの長さ

メッセージの転送長は、メッセージに表示されるメッセージ本文の長さです。つまり、転送コーディングが適用された後です。メッセージ本文がメッセージに含まれている場合、その本文の転送長は、次のいずれかによって決定されます (優先順)。

1. メッセージ本文を含めてはならない応答メッセージ (1xx、204、304 応答、および HEAD 要求への応答など) は、ヘッダー フィールドの後の最初の空行で常に終了します。メッセージに存在するエンティティ ヘッダー フィールド。

2. Transfer-Encoding ヘッダー フィールド (セクション 14.41) が存在し、「アイデンティティ」以外の値を持つ場合、転送長は「チャンクされた」転送コーディング (セクション 3.6) を使用して定義されます。接続を閉じることで終了します。

3. Content-Length ヘッダー フィールド (セクション 14.13) が存在する場合、OCTET の 10 進値は、エンティティの長さと転送長の両方を表します。これら 2 つの長さが異なる場合 (つまり、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.

4.メッセージがメディアタイプ「マルチパート/バイトレンジ」を使用し、転送長が特に指定されていない場合、この自己区切りメディアタイプが転送長を定義します。このメディア タイプは、受信者が解析できることを送信者が認識していない限り、使用してはなりません (MUST NOT)。1.1 クライアントからの複数のバイト範囲指定子を含む Range ヘッダーのリクエストに存在することは、クライアントが multipart/byteranges レスポンスを解析できることを意味します。

   A range header might be forwarded by a 1.0 proxy that does not
   understand multipart/byteranges; in this case the server MUST
   delimit the message using methods defined in items 1,3 or 5 of
   this section.

5.サーバーが接続を閉じることにより。(接続を閉じることは、サーバーが応答を送り返す可能性を残さないため、要求本文の終わりを示すために使用することはできません。)

HTTP/1.0 アプリケーションとの互換性のために、メッセージ本文を含む HTTP/1.1 リクエストには、サーバーが HTTP/1.1 準拠であることがわかっている場合を除き、有効な Content-Length ヘッダー フィールドを含める必要があります。リクエストにメッセージ本文が含まれていて、Content-Length が指定されていない場合、サーバーは、メッセージの長さを判断できない場合は 400 (不適切なリクエスト) で応答する必要があります。有効な Content-Length を受け取ります。

エンティティを受信するすべての HTTP/1.1 アプリケーションは、「チャンクされた」転送コーディング (セクション 3.6) を受け入れなければならないため、メッセージの長さが事前に決定できない場合に、このメカニズムをメッセージに使用できます。

メッセージには、Content-Length ヘッダー フィールドと非 ID 転送コーディングの両方を含めてはなりません。メッセージに非 ID 転送コーディングが含まれている場合、Content-Length は無視する必要があります。

メッセージ本文が許可されているメッセージで Content-Length が指定されている場合、そのフィールド値はメッセージ本文の OCTET の数と正確に一致する必要があります。HTTP/1.1 ユーザー エージェントは、無効な長さを受信して​​検出した場合、ユーザーに通知する必要があります。

ヘッダーをランダムに追加して、それらに従うことを期待することはできません (他のヘッダーが上書きされる可能性があります)。最初に生成されたオーバーライドする可能性のあるすべてのヘッダーを制御する必要があります。

この質問 ( How to make PHP generate Chunked response ) によると、「チャンク」を強制する良い方法は、Transfer-Encoding とflush. おそらく、これら2つは厳密には必要ありません。バッファリングを開始する前に、無関係なフラッシュがどこかにありますか?

于 2013-02-01T04:57:39.667 に答える
0

私の推測では、modules/http/http_filtersApache はデフォルトでContent-Length.

于 2013-01-30T04:03:34.647 に答える