代码之家  ›  专栏  ›  技术社区  ›  user434917

如何在HTTP响应完成之前读取响应流

  •  6
  • user434917  · 技术社区  · 16 年前

    当使用httpWebRequest对象发出请求时,我需要调用getResponse()方法来发送请求并返回响应。
    此方法的问题在于,在收到所有数据之前,它不会返回响应对象。假设我正在下载一个100MB的文件,在响应完成并且所有的100MB都被下载之前,我将无法读取它。
    我想要的是能够在响应流到达时立即读取这些字节,而无需等待响应完成。
    我知道我可以使用范围HTTP头,但它对我的情况不起作用。

    4 回复  |  直到 12 年前
        1
  •  8
  •   Community Mohan Dere    9 年前

    我认为这与@zachary的建议非常接近。它似乎起作用;实际上我认为用 using 正如@zachary所做的那样,“更好”。
    我的主要观点是我看不到 GetResponse() 你似乎在描述。

    此外,下面的代码只粗略地显示了所有事情的工作原理; 它不会将流读取到末尾 例如(除非巧合:)。但是,如果您将它复制粘贴到一个空的“控制台应用程序”(Visual Studio中的一个项目)中,它应该可以工作。

    您可以尝试使用一些“较短”的URL进行测试。这里的示例开始下载Debian发行版的ISO(超过600兆字节)。 对不起,Debian,我不是有意窃取你的带宽。 -&顺便问一句:有什么合理的方法可以用来测试这样的场景吗?

    代码的灵感来自 C# - How to read a continuous stream of XML over HTTP .

    namespace StreamReadWebRequest
    {
        using System;
        using System.Collections.Generic;
        using System.Text;
        using System.Net;
        using System.IO;
    
        class Program
        {
            static void Main(string[] args)
            {
                HttpWebRequest req;
                HttpWebResponse res = null;
    
                try
                {
                    req = (HttpWebRequest)WebRequest.Create(
                            "http://cdimage.debian.org/debian-cd/5.0.4/i386/iso-cd/debian-504-i386-CD-1.iso");
                    res = (HttpWebResponse)req.GetResponse();
                    Stream stream = res.GetResponseStream();
    
                    byte[] data = new byte[4096];
                    int read;
                    while ((read = stream.Read(data, 0, data.Length)) > 0)
                    {
                        Process(data, read);
                    }
                }
                finally
                {
                    if (res != null)
                        res.Close();
                }
                Console.In.Read();
            }
    
            private static void Process(byte[] data, int read)
            {
                Console.Out.Write(ASCIIEncoding.ASCII.GetString(data));
            }
        }
    }
    
        2
  •  3
  •   Artjom B.    12 年前

    我在寻找同样的东西:服务器流分块的XML数据,我需要一个C客户机,可以在服务器流时访问这些数据。我尝试了许多不同的方法来访问源(WebChannelFactory、WebClient、HTTPWebRequest/Response、TCPClient),但到目前为止都失败了。找到这个线程后,我将重点放在httpwebrequest/response上,在这里,我遇到的问题与下面的行阻塞的问题相同:

    HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
    

    正如阿蒂奥姆奇拉鲁所说,如果它阻塞了:有些事情是错误的,因为它不应该阻塞。现在重点是通过下载大型.iso文件来复制默认行为,我发现fiddler正在阻塞getResponse()方法!

    但是,在设置流之后(即已经调用了getResponse())打开fiddler没有问题,但是在HTTP GET期间,如果您发现getResponse()正在阻塞,请尝试关闭fiddler并查看您的应用程序现在是否继续正常流(即读取流)。

        3
  •  1
  •   Zachary    16 年前

    如果在读取时设置缓冲区大小,则可以分块读取数据…例子。。。

     // Get the response stream
     using(Stream resStream = response.GetResponseStream())
     {
    
            string parseString = null;
            int    count      = 0;
    
            do
            {
                // Read a chunk of data
                count = resStream.Read(buf, 0, buf.Length);
    
                if (count != 0)
                {
                    // Convert to ASCII
                    parseString = Encoding.ASCII.GetString(buf, 0, count);
    
                    // Append string to results
                    sb.Append(tempString);
                }
            }
            while (count > 0);
    
    }
    
        4
  •  0
  •   Community Mohan Dere    9 年前

    我不知道你这方面有什么,但我知道一个事实(我相信很多人会同意)。 GetResponse() 不会下载整个文件。它将发送请求,等待响应,并获取响应头。

    在得到响应之后,您可以很容易地使用 GetResponseStream() ,这是从服务器下载的实际数据流。在下载整个文件之前,您可以轻松地访问响应流。这是100%正确的,并且经过了测试。

    如果您没有得到相同的行为(这真的很奇怪,不应该发生),您是否可以添加一个不工作的代码示例,如我上面所解释的那样?

    另外,测试发布的示例 scherand . 它再一次证明了它的工作很好,没有任何特殊的黑客。