当使用 HttpWebRequest 对象发出请求时,我需要调用 GetResponse() 方法来发送请求并取回响应。
此方法的问题在于,在收到所有数据之前它不会返回响应对象。假设我正在下载一个 100 MB 的文件,在响应完成并下载所有 100 MB 之前,我将无法读取它。
我想要的是能够在响应流字节到达后立即读取它们,而无需等待响应完成。
我知道我可以使用 Range Http 标头,但它不适用于我的情况。
4 回答
我认为这非常接近@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));
}
}
}
我一直在寻找同样的东西:服务器流式传输分块的 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 并查看您的应用程序现在是否连续这是正常的流程(即读取流)。
如果您在读取时设置缓冲区大小,则可以分块读取数据...例如...
// 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);
}
我不确定你有什么,但我知道一个事实(我相信很多人会同意这里)GetResponse()
不会将整个文件下载回来。它将发送请求,等待响应,并获取响应标头。
得到响应后,您可以通过 轻松获取响应流GetResponseStream()
,这是从服务器下载的实际数据流。您可以在下载整个文件之前轻松访问响应流。这是 100% 真实且经过测试的。
如果您没有得到相同的行为(这真的很奇怪,而且不应该发生),您是否可以添加一个我上面解释的不起作用的代码示例?
另外,请测试scherand发布的示例。它再次证明它工作得很好,没有任何特殊的黑客攻击。