如果我想部分下载文件并在请求标题中定义单个范围,我明白了 响应正文中请求的文件的字节流。
但是,如果我指定多个范围如下,我总是为每个定义的范围获得额外的范围 响应头中的响应头(描述请求的范围)会破坏响应体 下载的文件。
static void Main(string[] args)
{
Console.Write("Please enter target File: ");
string Target = Console.ReadLine();
string Source = @"http://mozilla-mirror.3347.voxcdn.com/pub/mozilla.org/firefox/releases/3.6/win32/de/Firefox%20Setup%203.6.exe";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Source);
request.Credentials = CredentialCache.DefaultCredentials;
// define multiple Ranges
request.AddRange( 0, 1000000);
request.AddRange(1000000, 2000000);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (Stream source = response.GetResponseStream())
{
using (FileStream target = File.Open(Target, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
{
byte[] buffer = new byte[4096];
int BytesRead = 0;
int TotalBytesRead = 0;
while((BytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
{
target.Write(buffer, 0, BytesRead);
TotalBytesRead += BytesRead;
Console.WriteLine("{0}", TotalBytesRead);
}
}
}
Console.WriteLine("Downloading Finished!");
Console.ReadLine();
}
请求如Wireshark所示:
http://img197.imageshack.us/img197/8199/requesty.png
Response Body应仅包含文件的字节流,但在每个定义的范围的开头还包含不需要的Response-Header:
是否可以避免身体中的额外响应标题而不单独请求每个范围?
或
是否有内置方法来过滤其他响应标头,其大小可能因HTTP服务器而异?
答案 0 :(得分:1)
不,这就是HTTP / 1.1中多个范围的工作方式。请参阅RFC 2616, Section 19.2。
答案 1 :(得分:1)
感谢您的帮助,正如上面的链接所描述的那样 http http响应具有多个范围的请求。
左右....
是否可以避免身体中的额外响应标头 分别请求每个范围?
=>否。
是否有内置方法来过滤其大小的附加响应标头 可能因HTTP服务器而异?
=>我不知道但是......
也许你们中的一些人可能会批评下面的代码块 过滤文件数据中的标题:
public void DoDownload(Range[] Ranges)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_Source);
request.Credentials = CredentialCache.DefaultCredentials;
foreach (Range r in Ranges)
{
request.AddRange(r.From, r.To);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string boundary = "";
Match m = Regex.Match(response.ContentType, @"^.*boundary=(?<boundary>.*)$");
if (m.Success)
{
boundary = m.Groups["boundary"].Value;
}
else
{
throw new InvalidDataException("invalid packet data: no boundary specification found.");
}
using (Stream source = response.GetResponseStream())
{
using (FileStream target = File.Open(m_TargetFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
{
// buffer for payload
byte[] buffer = new byte[4096];
// buffer for current range header
byte[] header = new byte[200];
// next header after x bytes
int NextHeader = 0;
// current position in header[]
int HeaderPosition = 0;
// current position in buffer[]
int BufferPosition = 0;
// left data to proceed
int BytesToProceed = 0;
// total data written without range-headers
long TotalBytesWritten = 0;
// count of last data written to target file
int BytesWritten = 0;
// size of processed header data
int HeaderSize = 0;
// count of last data read from ResponseStream
int BytesRead = 0;
while ((BytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
{
BufferPosition = 0;
BytesToProceed = BytesRead;
HeaderSize = 0;
while (BytesToProceed > 0)
{
if (NextHeader == 0)
{
for (;HeaderPosition < header.Length; HeaderPosition++, BufferPosition++, HeaderSize++)
{
if (BytesToProceed > HeaderPosition && BufferPosition < BytesRead)
{
header[HeaderPosition] = buffer[BufferPosition];
if (HeaderPosition >= 4 &&
header[HeaderPosition - 3] == 0x0d &&
header[HeaderPosition - 2] == 0x0a &&
header[HeaderPosition - 1] == 0x0d &&
header[HeaderPosition] == 0x0a)
{
string RangeHeader = Encoding.ASCII.GetString(header, 0, HeaderPosition + 1);
Match mm = Regex.Match(RangeHeader,
@"^\r\n(--)?" + boundary + @".*?(?<from>\d+)\s*-\s*(?<to>\d+)/.*\r\n\r\n", RegexOptions.Singleline);
if (mm.Success)
{
int RangeStart = Convert.ToInt32(mm.Groups["from"].Value);
int RangeEnd = Convert.ToInt32(mm.Groups["to"].Value);
NextHeader = (RangeEnd - RangeStart) + 1;
target.Seek(RangeStart, SeekOrigin.Begin);
BufferPosition++;
BytesToProceed -= HeaderSize + 1;
HeaderPosition = 0;
HeaderSize = 0;
break;
}
else { throw new InvalidDataException("invalid header: missing range specification.");}
}
}
else { goto READ_NEW; }
}
if (NextHeader == 0)
throw new InvalidDataException("invalid packet data: no range-header found.");
}
BytesWritten = (NextHeader > BytesToProceed) ? BytesToProceed : NextHeader;
target.Write(buffer, BufferPosition, BytesWritten);
BytesToProceed -= BytesWritten;
NextHeader -= BytesWritten;
BufferPosition += BytesWritten;
TotalBytesWritten += BytesWritten;
}
READ_NEW:;
}
}
}
}
并且如果有另一种/更好的方法可以给我一些提示。
最好的问候 cap_Chap