8

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

4

4 回答 4

11

我认为这非常接近@Zachary 的建议。它(似乎)有效;实际上,我认为使用using@Zachary 所做的甚至“更好”。
我的主要观点是我看不到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));
        }
    }
}
于 2010-05-18T11:58:43.030 回答
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 并查看您的应用程序现在是否连续这是正常的流程(即读取流)。

于 2014-07-23T12:45:35.787 回答
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);

}
于 2010-05-16T05:43:51.930 回答
1

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

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

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

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

于 2010-05-18T13:15:06.150 回答