8

だから私はMVCプロジェクトを持っています。この MVC プロジェクトには、コンテンツをクライアントにストリーミングする必要がある 1 つのコントローラーが含まれています。ストリーミングの開始時に、コンテンツの長さを決定する方法はありません (オンザフライで計算されます)。そこで、HttpContext.Current.Response.OutputStream を開き、定期的に書き込みとフラッシュを開始します (既にバッファー出力を無効にし、適切な http ヘッダーを添付しています)。

while (some condition){

   HttpContext.Current.Response.OutputStream.Write(buffer, 0, buffer.Length);
   HttpContext.Current.Response.Flush();
}

次に、ストリームを強制的に閉じると:

HttpContext.Current.Response.Close();

Chunked コンテンツを適切に終了しません (クライアントに EOF を示すために、最後に長さ 0 のチャンクを追加しません)。

代わりに、出力ストリームをより適切に閉じると:

HttpContext.Current.Response.End();

また

HttpContext.Current.ApplicationInstance.CompleteRequest();

ストリームを適切に閉じます (最後に長さゼロのチャンクが追加されます) が、ストリームが既に書き込まれているため、HTTP ヘッダーを出力ストリームに挿入できないことを示す例外がアプリケーションによってスローされます。

どちらの場合も、Controller は null (または EmptyActionResult) を返します。

MVC スタックでは、コントローラーの実行が終了した後にすべての ActionResult が HTTP ヘッダーを設定する必要があるため、例外が発生したと思います。この場合、MVC でチャンク ストリームをどのように実装しますか?

前もって感謝します!

編集:スローされる正確な例外は次のとおりです。

Uncaught Exception: System.Web.HttpException (0x80004005): Server cannot set status after HTTP headers have been sent.
   at System.Web.Http.WebHost.HttpControllerHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.Http.WebHost.HttpControllerHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 
4

1 に答える 1

3

解決策を見つけました。

HTTP 1.1 標準では、要求モードがキープアライブの場合にのみ、チャンク エンコーディングを長さ 0 のチャンクで閉じる必要があると指定されています。

キープアライブ モードでは、クライアント/サーバー間の接続は、複数の要求/応答に対して永続化されます。チャンク エンコーディングは、このコンテキストでは長さ 0 のチャンクで終了する必要があります。これは、クライアントが前の応答がいつ終了したかを知る方法が他にないためです。

"Connection: keep-alive" ではなく、"Connection: close" をヘッダーとして指定すると、接続はリクエスト間で保持されず、クライアントは接続の終了をレスポンス終了の表示として使用できます。 EOF を示す長さ 0 のチャンク。

以下を使用して HttpResponse を手動で閉じることにしました。

HttpContext.Current.Response.Close();

接続が EOF で閉じることをクライアントに伝えるためにコードで以前に指定している間。これにより、クライアントが 0 の長さのチャンクを受信して​​いなかった問題が解決されました。これは、クライアントがそれを必要としなくなったためです。

于 2013-07-25T17:11:44.920 に答える