使用HttpWebResponse读取“chunked”响应

当使用StreamReader读取HttpWebResponse的GetResponseStream()返回的流时,我在读取“chunked”响应时遇到问题:

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

reader.ReadToEnd()方法时,我得到以下System.IO.IOException: 无法从传输连接读取数据:连接已关闭。

当服务器返回“非分块”响应时,上面的代码工作得很好。

我能够让它工作的唯一方法是使用HTTP / 1.0作为初始请求(而不是默认的HTTP / 1.1),但这似乎是一种蹩脚的解决方法。

有任何想法吗?


@Chuck

你的解决方案非常好用。 它仍然在最后一个Read()上抛出相同的IOExeception。 但在检查StringBuilder的内容后,看起来已经收到了所有数据。 所以也许我只需要在try-catch中包装Read()并吞下“错误”。

没有用“chunked”响应尝试这个,但是这样的工作呢?

 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和重定向,但它们不会自动处理响应主体上的分块内容。

这可能是因为分块内容可能包含的不仅仅是简单数据(即:块名称,尾部标题)。

简单地读取流并忽略EOFexception将不起作用,因为流包含的内容多于所需内容。 流将包含块,每个块首先声明其大小。 如果简单地从头到尾读取流,则最终数据将包含块元数据(并且在其为gziped内容的情况下,它将在解压缩时失败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); 

这有点像黑客,但是如果最后一次读取是杀了你而且它没有返回任何数据,那么理论上这将避免这个问题。 我仍然想知道为什么流正在这样做。

我遇到了同样的问题(这就是我最终的结果:-)。 最终将其追溯到分块流无效的事实 – 最后的零长度块丢失了。 我想出了以下代码,它处理有效和无效的分块流。

 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(); }