代码之家  ›  专栏  ›  技术社区  ›  Joe Philllips

使用HttpWebResponse读取“分块”响应

  •  14
  • Joe Philllips  · 技术社区  · 17 年前

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

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

    时中 reader.ReadToEnd() 方法被称为“我得到以下系统”。IO.IO异常: 无法从传输连接读取数据:连接已关闭。

    当服务器返回“非分块”响应时,上述代码运行良好。

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

    有什么想法吗?


    @查克

    你的解决方案相当不错。它仍然在最后一次Read()时抛出相同的IOExeception。但是在检查StringBuilder的内容后,看起来所有数据都已收到。因此,也许我只需要将Read()封装在try-catch中并吞下“错误”。

    5 回复  |  直到 14 年前
        1
  •  3
  •   Brian M. Hunt    17 年前

    还没有尝试过这种“分块”响应,但这样的方法有效吗?

    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);
    
        2
  •  1
  •   user2186152    13 年前

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

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

    简单地读取流并忽略EOF异常是行不通的,因为流包含的内容超过了所需的内容。流将包含块,每个块都以声明其大小开始。如果只是从头到尾读取流,则最终数据将包含块元数据(如果是gzip压缩的内容,则解压缩时CRC校验将失败)。

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

    有用资源:

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

        3
  •  -1
  •   Brian M. Hunt    17 年前

    在尝试了StackOverflow和谷歌的大量代码片段后,我最终发现这是最有效的(假设你知道数据是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-chunked?forum=ncl

        4
  •  -1
  •   Liam Corner    17 年前

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

    推荐文章