读“分块” 使用 HttpWebResponse 进行响应

发布于 2024-07-04 07:57:30 字数 681 浏览 9 评论 0原文

当使用 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.0 进行初始请求(而不是默认的 HTTP/1.1),但这似乎是一个蹩脚的解决方法。

有任何想法吗?


@Chuck

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

I'm having trouble reading a "chunked" response when using a StreamReader to read the stream returned by GetResponseStream() of a HttpWebResponse:

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

When the reader.ReadToEnd() method is called I'm getting the following System.IO.IOException: Unable to read data from the transport connection: The connection was closed.

The above code works just fine when server returns a "non-chunked" response.

The only way I've been able to get it to work is to use HTTP/1.0 for the initial request (instead of HTTP/1.1, the default) but this seems like a lame work-around.

Any ideas?


@Chuck

Your solution works pretty good. It still throws the same IOExeception on the last Read(). But after inspecting the contents of the StringBuilder it looks like all the data has been received. So perhaps I just need to wrap the Read() in a try-catch and swallow the "error".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绻影浮沉 2024-07-11 07:57:30

在尝试了 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());

我发现其他变体最有效的时间,但偶尔会截断数据。 我从以下位置获取此片段:

https://social.msdn.microsoft.com/Forums/en-US/4f28d99d-9794-434b-8b78-7f9245c099c4/problems-with-httpwebrequest-and-transferencoding-分块?forum=ncl

After trying a lot of snippets from StackOverflow and Google, ultimately I found this to work the best (assuming you know the data a UTF8 string, if not, you can just keep the byte array and process appropriately):

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

I found other variations work most of the time, but occasionally truncate the data. I got this snippet from:

https://social.msdn.microsoft.com/Forums/en-US/4f28d99d-9794-434b-8b78-7f9245c099c4/problems-with-httpwebrequest-and-transferencoding-chunked?forum=ncl

不爱素颜 2024-07-11 07:57:30

我正在研究类似的问题。 .net HttpWebRequest 和 HttpWebRequest 自动处理 cookie 和重定向,但它们不会自动处理响应正文上的分块内容。

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

简单地读取流并忽略 EOF 异常是行不通的,因为流包含的内容多于所需的内容。 流将包含块,每个块首先声明其大小。 如果只是从头到尾读取流,则最终数据将包含块元数据(如果是 gzip 内容,则在解压缩时将无法通过 CRC 检查)。

为了解决这个问题,需要手动解析流,从每个块中删除块大小(以及 CR LF 分隔符),检测最终块并仅保留块数据。 可能有一个图书馆可以做到这一点,但我还没有找到。

有用的资源:

http://en.wikipedia.org/wiki/Chunked_transfer_encoding
https://www.rfc-editor.org/rfc/rfc2616#第3.6.1节

I am working on a similar problem. The .net HttpWebRequest and HttpWebRequest handle cookies and redirects automatically but they do not handle chunked content on the response body automatically.

This is perhaps because chunked content may contain more than simple data (i.e.: chunk names, trailing headers).

Simply reading the stream and ignoring the EOF exception will not work as the stream contains more than the desired content. The stream will contain chunks and each chunk begins by declaring its size. If the stream is simply read from beginning to end the final data will contain the chunk meta-data (and in case where it is gziped content it will fail the CRC check when decompressing).

To solve the problem it is necessary to manually parse the stream, removing the chunk size from each chunk (as well as the CR LF delimitors), detecting the final chunk and keeping only the chunk data. There likely is a library out there somewhere that does this, I have not found it yet.

Usefull resources :

http://en.wikipedia.org/wiki/Chunked_transfer_encoding
https://www.rfc-editor.org/rfc/rfc2616#section-3.6.1

分开我的手 2024-07-11 07:57:30

还没有尝试过“分块”响应,但是这样的东西会起作用吗?

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

Haven't tried it this with a "chunked" response but would something like this work?

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);
ㄟ。诗瑗 2024-07-11 07:57:30

我也遇到了同样的问题(这就是我最终来到这里的原因:-)。 最终追踪到分块流无效的事实 - 最终的零长度块丢失。 我想出了以下代码来处理有效和无效的分块流。

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

I've had the same problem (which is how I ended up here :-). Eventually tracked it down to the fact that the chunked stream wasn't valid - the final zero length chunk was missing. I came up with the following code which handles both valid and invalid chunked streams.

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();
}
雨落□心尘 2024-07-11 07:57:30

这很有趣。 在处理请求标头并删除“Accept-Encoding: gzip,deflate”期间,我的用例中的服务器确实以简单的 ascii 方式进行应答,而不再使用分块的编码片段。 也许你应该尝试一下并保留“Accept-Encoding: gzip,deflate”。 这个想法是在阅读上面提到的 wiki 中有关使用压缩的主题时产生的。

It is funny. During playing with the request header and removing "Accept-Encoding: gzip,deflate" the server in my usecase did answer in a plain ascii manner and no longer with chunked, encoded snippets. Maybe you should give it a try and keep "Accept-Encoding: gzip,deflate" away. The idea came while reading the upper mentioned wiki in topic about using compression.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文