在处理HTTP网络请求时,有时会遇到一些棘手的问题,比如Content-Length的值为-1。这种情况通常发生在使用分块传输编码(chunked transfer encoding)时,数据长度超过了某个阈值。尽管网络上的搜索结果并没有给出一个明确的解决方案,但通过使用Fiddler2工具进行测试,推测出了可能的原因,尽管不能确定这就是最终答案。
以下是两个HTTP响应的示例,其中一个的Content-Length是正确的,而另一个则出现了问题。
正确的Content-Length响应:
HTTP/1.1 200 OK
Date: Tue, 01 Jan 2013 21:48:42 GMT
Server: Apache
Content-Disposition: attachment; filename="example.file"
Content-Length: 1537
Content-Type: application/octet-stream
Content-Language: fr-FR
Via: 1.1 some.proxy.server
X-Cache: MISS from some.proxy.server
Keep-Alive: timeout=15, max=90
Connection: Keep-Alive
Content-Length值错误的响应:
HTTP/1.1 200 OK
Date: Tue, 01 Jan 2013 21:48:44 GMT
Server: Apache
Content-Disposition: attachment; filename="example.file"
Content-Type: application/octet-stream
Content-Language: fr-FR
Via: 1.1 some.proxy.server
X-Cache: MISS from some.proxy.server
Keep-Alive: timeout=15, max=86
Connection: Keep-Alive
Content-Length: 13356
不清楚也不关心为什么HTTP服务器不总是按相同的顺序返回响应头(是否由分块数据引起?),但怀疑.NET Framework(4.0版本)在Content-Length头出现在Connection头之后时会忽略它(如上所示的HTTP响应)。
为了解决这个问题,决定忽略Content-Length头,让MemoryStream动态增长,这似乎解决了问题。
这种方法虽然有效,但是否有更好的解决方案或建议呢?
在.NET Framework中,MemoryStream类提供了一种动态管理内存的方式,允许在不知道数据大小的情况下读取数据。这种方法避免了在读取HTTP响应时遇到Content-Length为-1的问题。
using System.IO;
using System.Net;
public byte[] DownloadData(string url)
{
byte[] buffer = new byte[1024];
using (MemoryStream ms = new MemoryStream())
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) != 0)
{
ms.Write(buffer, 0, bytesRead);
}
}
}
return ms.ToArray();
}
}
在上述代码中,创建了一个MemoryStream对象,并使用一个循环读取响应流中的数据。每次读取到数据后,将其写入MemoryStream中。最后,调用ToArray方法将MemoryStream中的数据转换为一个字节数组。
分块传输编码是一种HTTP传输编码,它允许服务器在不知道整个响应内容大小的情况下发送数据。在处理分块传输编码时,服务器会在每个数据块的开始处指定该块的大小,而不是在响应头中指定Content-Length。
为了正确处理分块传输编码,需要逐块读取数据,而不是依赖Content-Length头。以下是一个处理分块传输编码的示例代码:
using System.IO;
using System.Net;
public byte[] DownloadChunkedData(string url)
{
byte[] buffer = new byte[1024];
using (MemoryStream ms = new MemoryStream())
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.TransferEncoding = "chunked";
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) != 0)
{
ms.Write(buffer, 0, bytesRead);
}
}
}
return ms.ToArray();
}
}