这里真正重要的是“范围”标题。尽管现有答案是正确的,但它没有任何解释。
当您在未指定范围的情况下发出请求时,将流式传输整个文件。视频播放器会根据播放器在视频中的位置自动指定带有起始字节的“范围”标头。
由于这本质上是 HTTP 的一部分,因此它在RFC 7233中有很好的记录。
'Accept-Range: bytes' 标头告诉客户端我们希望接受范围标头作为字节数。状态码“206”告诉客户端我们发送了部分内容,也就是整个文件的一部分。“Content-Range: start-end/total”标头告诉客户端我们在当前请求中发回的信息范围。
这是一个功能齐全的片段:
public static void RespondFile(this HttpListenerContext context, string path, bool download = false) {
HttpListenerResponse response = context.Response;
// tell the browser to specify the range in bytes
response.AddHeader("Accept-Ranges", "bytes");
response.ContentType = GetMimeType(path);
response.SendChunked = false;
// open stream to file we're sending to client
using(FileStream fs = File.OpenRead(path)) {
// format: bytes=[start]-[end]
// documentation: https://www.rfc-editor.org/rfc/rfc7233#section-4
string range = context.Request.Headers["Range"];
long bytes_start = 0,
bytes_end = fs.Length;
if (range != null) {
string[] range_info = context.Request.Headers["Range"].Split(new char[] { '=', '-' });
bytes_start = Convert.ToInt64(range_info[1]);
if (!string.IsNullOrEmpty(range_info[2]))
bytes_end = Convert.ToInt64(range_info[2]);
response.StatusCode = 206;
response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", bytes_start, bytes_end - 1, fs.Length));
}
// determine how many bytes we'll be sending to the client in total
response.ContentLength64 = bytes_end - bytes_start;
// go to the starting point of the response
fs.Seek(bytes_start, SeekOrigin.Begin);
// setting this header tells the browser to download the file
if (download)
response.AddHeader("content-disposition", "attachment; filename=" + Path.GetFileName(path));
// stream video to client
// note: closed connection during transfer throws exception
byte[] buffer = new byte[HttpServer.BUFFER_SIZE];
int bytes_read = 0;
try {
while (fs.Position < bytes_end) {
bytes_read = fs.Read(buffer, 0, buffer.Length);
response.OutputStream.Write(buffer, 0, bytes_read);
}
response.OutputStream.Close();
} catch(Exception) {}
}
}
请注意,我们可以简单地检查文件流的“位置”(以字节为单位),而不是跟踪我们总共发送了多少字节。