我目前正在尝试响应HTTP Range Requests的过程,以便可以从我们的服务器流式传输视频,并满足Safari实际播放视频的要求。
我确实增加了复杂性,即视频文件已在磁盘上加密,这使我无法进入Seek
流中,但这实际上不在此问题的范围之内。
我注意到,Chrome和至少新的Edge请求打开范围(0-)。正确的答案是什么?目前,我以完整的视频作为回应,据我所知,这完全违背了流媒体的目的。
var range = context.Request.Headers["Range"].Split('=', '-');
var startByteIndex = int.Parse(range[1]);
// Quite a few browers send open ended requests for the range (e.g. 0- ).
long endByteIndex;
if (!long.TryParse(range[2], out endByteIndex))
{
endByteIndex = streamLength - 1;
}
到目前为止,以下是我的完整尝试。
if (!string.IsNullOrEmpty(context.Request.Headers["Range"]))
{
var range = context.Request.Headers["Range"].Split('=', '-');
var startByteIndex = int.Parse(range[1]);
// Quite a few browers send open ended requests for the range (e.g. 0- ).
long endByteIndex;
if (!long.TryParse(range[2], out endByteIndex))
{
endByteIndex = streamLength - 1;
}
Debug.WriteLine("Range request for " + context.Request.Headers["Range"]);
// Make sure the request is within the bounds of the video.
if (endByteIndex >= streamLength)
{
context.Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
return false;
}
var currentIndex = 0;
// SEEKING IS NOT WHOLE AND COMPLETE.
// Get to the requested start. We are not allowed to seek with CBC + AES.
while (currentIndex < startByteIndex) // TODO: we could probably work out a more suitable buffer size here to get to the start index.
{
var dummy = new byte[bufferLength];
var a = videoReadStream.Read(dummy, 0, bufferLength);
currentIndex += bufferLength;
}
// Fast but unreliable given AES + CBC.
//fileStream.Seek(startByteIndex, SeekOrigin.Begin);
dataToRead = endByteIndex - startByteIndex + 1;
// Supply the relevant partial content headers.
context.Response.StatusCode = (int)HttpStatusCode.PartialContent;
context.Response.AddHeader("Content-Range", $"bytes {startByteIndex}-{endByteIndex}/{streamLength}");
context.Response.AddHeader("Content-Length", dataToRead.ToString());
}
else
{
context.Response.AddHeader("Cache-Control", "private, max-age=1200");
context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(20));
context.Response.AddHeader("content-disposition", "inline;filename=" + fileID);
context.Response.AddHeader("Accept-Ranges", "bytes");
}
var buffer = new byte[bufferLength];
while (dataToRead > 0 && context.Response.IsClientConnected)
{
videoReadStream.Read(buffer, 0, bufferLength);
// Write the data to the current output stream.
context.Response.OutputStream.Write(buffer, 0, bufferLength);
// Flush the data to the HTML output.
context.Response.Flush();
buffer = new byte[bufferLength];
dataToRead -= bufferLength;
}
最令人沮丧的是,我注意到Edge(我还没有测试其他人)似乎总是发送一个打开的请求
Range request for bytes=0-
Range request for bytes=1867776-
Range request for bytes=3571712-
Range request for bytes=5341184-
Range request for bytes=7176192-
Range request for bytes=9273344-
Range request for bytes=10977280-
Range request for bytes=12943360-
Range request for bytes=14614528-
Range request for bytes=16384000-
Range request for bytes=18087936-
Range request for bytes=19955712-
Range request for bytes=21823488-
Range request for bytes=23625728-
Range request for bytes=25690112-
Range request for bytes=27525120-
Range request for bytes=39256064-
Range request for bytes=41222144-
Range request for bytes=42270720-
我是否应该决定要响应的块大小并坚持使用?我注意到,如果我确实只回答了3个大小的块,那么Edge确实要求以3为增量的更多范围。
这与字节范围0-表示类似但不完全相同的问题。
正确的答案是什么?
正确的响应是整个资源。但是,由于此客户端包括Range
标头,因此你也可以使用206 Partial content
和文件的子集进行响应。
我是否应该决定要响应的块大小并坚持使用?
差不多,这取决于服务器的效率。请注意,由于在Firefox中接收到具有指定内容范围的206之后,它将不再请求其他数据,因此你可能会遇到浏览器执行不正确的操作。
感谢您的回答。当您说“您可能会遇到浏览器执行的操作不正确”时,您肯定是正确的:)。