如何最好地响应开放的 HTTP 范围请求
How best to respond to an open HTTP range request
我目前正在尝试响应 HTTP 范围请求,以便可以从我们的服务器流式传输视频并满足 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 为增量请求更多范围。
这是一个与 What byte range 0- means 相似但不完全相同的问题。
What is the correct thing to respond with here?
此处正确的响应是整个资源。但是,由于此客户端包含 Range
header,您可以 也 响应 206 Partial content
和文件的子集。
Should I just decide on a chunk size to respond with and stick with that?
差不多,这取决于您的服务器的效率。请注意,与 Firefox won't request further data after receiving 206 with specified content range 一样,您可能会遇到浏览器不正确的情况。
我目前正在尝试响应 HTTP 范围请求,以便可以从我们的服务器流式传输视频并满足 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 为增量请求更多范围。
这是一个与 What byte range 0- means 相似但不完全相同的问题。
What is the correct thing to respond with here?
此处正确的响应是整个资源。但是,由于此客户端包含 Range
header,您可以 也 响应 206 Partial content
和文件的子集。
Should I just decide on a chunk size to respond with and stick with that?
差不多,这取决于您的服务器的效率。请注意,与 Firefox won't request further data after receiving 206 with specified content range 一样,您可能会遇到浏览器不正确的情况。