使用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的内容后,看起来已经收到了所有数据。所以也许我只需要将read()包装在try-catch中并吞下“错误”。
答案 0 :(得分:3)
没有用“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);
答案 1 :(得分:1)
我正在研究类似的问题。 .net HttpWebRequest和HttpWebRequest自动处理cookie和重定向,但它们不会自动处理响应主体上的分块内容。
这可能是因为分块内容可能包含的不仅仅是简单数据(即:块名称,尾部标题)。
简单地读取流并忽略EOF异常将不起作用,因为流包含的内容超过了所需的内容。流将包含块,每个块首先声明其大小。如果简单地从头到尾读取流,则最终数据将包含块元数据(如果它是gziped内容,则在解压缩时将无法通过CRC检查)。
要解决此问题,必须手动解析流,从每个块(以及CR LF分隔符)中删除块大小,检测最终块并仅保留块数据。可能有一个库在那里做到了这一点,我还没有找到它。
有用的资源:
http://en.wikipedia.org/wiki/Chunked_transfer_encoding http://tools.ietf.org/html/rfc2616#section-3.6.1
答案 2 :(得分:0)
尝试了StackOverflow和Google的很多代码片段后,最终我发现这是最好的方法(假设您知道数据为UTF8字符串,如果没有,则可以保留字节数组并进行适当处理):
byte[] data;
var responseStream = response.GetResponseStream();
var reader = new StreamReader(responseStream, Encoding.UTF8);
data = Encoding.UTF8.GetBytes(reader.ReadToEnd());
return Encoding.Default.GetString(data.ToArray());
我发现大多数时候其他版本都可以工作,但偶尔会截断数据。我从以下位置得到了这段代码:
答案 3 :(得分:-1)
Craig,没有看到你正在阅读它的流有点难以调试,但可能你可以将count变量的设置更改为:
count = resStream.Read(buf, 0, buf.Length-1);
这有点像黑客攻击,但是如果最后一次读取是在杀死你并且它没有返回任何数据,那么理论上这将避免这个问题。我仍然想知道为什么流正在这样做。
答案 4 :(得分:-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();
}