質問

StreamReader を使用して HttpWebResponse の GetResponseStream() によって返されたストリームを読み取るときに、「チャンクされた」応答を読み取ることができません。

// response is an HttpWebResponse
StreamReader reader = new StreamReader(response.GetResponseStream());
string output = reader.ReadToEnd(); // throws exception...

とき reader.ReadToEnd() メソッドが呼び出されると、次の System.IO.IOException が発生します。 トランスポート接続からデータを読み取ることができません:接続が閉じられました。

上記のコードは、サーバーが「非チャンク」応答を返した場合に問題なく動作します。

これを動作させることができた唯一の方法は、最初のリクエストに (デフォルトの HTTP/1.1 ではなく) HTTP/1.0 を使用することですが、これは不十分な回避策のように思えます。

何か案は?


@チャック

あなたのソリューションはかなりうまく機能します。最後の Read() でも同じ IOException がスローされます。しかし、StringBuilder の内容を検査すると、すべてのデータが受信されていることがわかります。したがって、おそらく Read() を try-catch でラップし、「エラー」を飲み込む必要があるだけです。

役に立ちましたか?

解決

「チャンク」応答でこれを試したことはありませんが、このようなものは機能しますか?

StringBuilder sb = new StringBuilder();
Byte[] buf = new byte[8192];
Stream resStream = response.GetResponseStream();
string tmpString = null;
int count = 0;
do
{
     count = resStream.Read(buf, 0, buf.Length);
     if(count != 0)
     {
          tmpString = Encoding.ASCII.GetString(buf, 0, count);
          sb.Append(tmpString);
     }
}while (count > 0);

他のヒント

私も同様の問題に取り組んでいます。.net HttpWebRequest および HttpWebRequest は、Cookie とリダイレクトを自動的に処理しますが、応答本文のチャンク化されたコンテンツは自動的に処理しません。

これはおそらく、チャンク化されたコンテンツには単純なデータ以上のデータが含まれる可能性があるためです (例:チャンク名、末尾のヘッダー)。

ストリームには必要以上のコンテンツが含まれているため、単にストリームを読み取って EOF 例外を無視するだけでは機能しません。ストリームにはチャンクが含まれ、各チャンクはサイズを宣言することから始まります。ストリームが最初から最後まで単純に読み取られる場合、最終データにはチャンク メタデータが含まれます (また、それが gzip 圧縮されたコンテンツの場合は、解凍時に CRC チェックに失敗します)。

この問題を解決するには、ストリームを手動で解析し、各チャンクからチャンク サイズ (CR LF デリミタも同様) を削除し、最後のチャンクを検出してチャンク データのみを保持する必要があります。おそらくこれを行うライブラリがどこかにあると思いますが、私はまだ見つけていません。

役立つリソース:

http://en.wikipedia.org/wiki/Chunked_transfer_encoding http://tools.ietf.org/html/rfc2616#section-3.6.1

Craig、読んでいるストリームを見ずにデバッグするのは少し難しいですが、count 変数の設定を次のように変更できるかもしれません。

count = resStream.Read(buf, 0, buf.Length-1);

これはちょっとしたハックですが、最後の読み取りでエラーが発生し、データが返されない場合は、理論的にはこれで問題を回避できます。なぜストリームがそのようなことをするのか今でも疑問に思っています。

私も同じ問題を抱えていました(これが私がここにたどり着いた経緯です:-)。最終的に、チャンク化されたストリームが有効ではない、つまり最後の長さ 0 のチャンクが欠落しているという事実が突き止められました。有効なチャンクストリームと無効なチャンクストリームの両方を処理する次のコードを思いつきました。

using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
    StringBuilder sb = new StringBuilder();

    try
    {
        while (!sr.EndOfStream)
        {
            sb.Append((char)sr.Read());
        }
    }
    catch (System.IO.IOException)
    { }

    string content = sb.ToString();
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top