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

8
使用HttpWebRequest对象发送请求时,需要调用GetResponse()方法来发送请求并获取响应。
这个方法的问题在于,它只有在接收到所有数据后才返回响应对象。比如说我正在下载一个100MB的文件,只有在响应完成并且所有100MB都下载完毕后,我才能读取它。
我希望能够在收到响应流字节时立即读取它们,而不必等待响应完成。
我知道可以使用Range Http头,但在我的情况下它行不通。

2
GetResponse() 或者你为 BeginGetResponse() 提供的回调函数会在所有响应头被读取后立即被调用,但除非响应非常小或者你读取它,否则整个响应不会被读取。 - Gonzalo
不清楚原帖作者是否已经测试过任何建议的解决方案并遇到了任何具体问题。根据我的经验,get response stream只获取流,当你从该流中读取时,响应会被下载,除非它是一个小块! - Charles Prakash Dasari
4个回答

12

我认为这非常接近@Zachary建议的内容,而且它(似乎)起作用了; 实际上,我认为像@Zachary一样使用using甚至更好。

我的主要观点是我看不到你(似乎)描述的GetResponse()的阻塞行为。

此外,以下代码仅大致显示了所有内容的工作方式;例如,它不会将流读取到末尾(除非偶然发生:))。但是,如果您将其复制并粘贴到Visual Studio中的空“控制台应用程序”项目中,则应该可以正常工作。

您可以尝试使用一些“较短”的URL进行测试。此示例开始下载debian发行版的ISO(略大于600 MByte)。抱歉debian,我不想占用你的带宽。另外:有没有什么明智的东西可以用来测试这种情况?

该代码受到C# - 如何在HTTP上读取连续的XML流的强烈启发。

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

同 scherand 所说的一样 :) - War

3
我正在寻找同样的东西:服务器流式传输分块XML数据,我需要一个能够在服务器流式传输时访问这些数据的C#客户端。我尝试了许多不同的方法来访问源代码(WebChannelFactory、WebClient、HttpWebRequest / Response、TcpClient),但迄今为止都失败了。找到这个线程后,我专注于HttpWebRequest / Response,在那里我有同样的问题,即以下行会阻塞:
HttpWebResponse resp = (HttpWebResponse)request.GetResponse();

如Artiom Chilaru所说,如果它是阻塞的:那么有些不对劲了,因为它本不应该这样。现在专注于尝试复制使用下载大型.ISO文件的默认行为,我发现Fiddler正在阻止GetResponse()方法!
但是,一旦建立起流(即已经调用GetResponse()),打开Fiddler就没有问题,但在HTTP GET期间,如果您发现GetResponse()阻塞,请尝试关闭Fiddler并查看您的应用程序是否继续正常运行(即读取流)。

1
这正是我的问题。一旦我关闭了Fiddler,GetResponse()就按预期运行了。谢谢! - Ray Ackley
我知道这是一个旧帖子,但是我也想发表一下我的看法。Fiddler实际上是一个代理服务器,因此它会获取来自原始服务器的整个响应,然后执行您期望它执行的操作。这就是为什么它会被阻止的原因。 - M22an

1

如果在读取时设置缓冲区大小,就可以按块读取数据...例如...

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

}

这是在响应完成后,我想要能够在此之前读取响应流。 - user434917

1

我不确定你那边的情况,但我知道一个事实(我相信很多人都会同意),GetResponse()不会下载整个文件。它会发送请求,等待响应,并获取响应头。

在获得响应后,您可以轻松使用GetResponseStream()获取响应流,这是从服务器下载的实际数据流。您可以在整个文件下载之前轻松访问响应流。这是100%真实和经过测试的。

如果您没有获得与上述相同的行为(这确实很奇怪,不应该发生),您可以添加一个代码示例,说明未按照我上面所解释的方式工作?

此外,请测试scherand发布的示例。它再次证明它可以正常工作,无需任何特殊技巧。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接