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

用httpwebresponse读取“chunked”响应

  •  12
  • Joe Philllips  · 技术社区  · 16 年前

    当使用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),但这似乎是一个蹩脚的工作。

    有什么想法吗?


    卡盘

    你的解决方案很有效。它仍然在最后一次读取()时抛出相同的ioexeception。但是在检查了StringBuilder的内容之后,看起来所有的数据都已经收到了。所以我可能只需要将read()包装在一个try-catch中,并接受“错误”。

    4 回复  |  直到 11 年前
        1
  •  3
  •   Brian M. Hunt    16 年前

    还没有尝试过用“块状”的回答,但像这样的工作吗?

    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    11 年前

    我正在研究一个类似的问题。.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

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

    Craig,如果没有看到您正在读取的流,调试起来有点困难,但是您可以将count变量的设置更改为:

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

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

        4
  •  -1
  •   Liam Corner    16 年前

    我也有同样的问题(我就是这样结束的:—)。最终跟踪到块流无效这一事实——最后的零长度块丢失了。我想出了以下代码来处理有效和无效的分块流。

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