如何最好地响应打开的HTTP范围请求

问题描述

我目前正在尝试响应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,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,bufferLength);

    // Write the data to the current output stream.
    context.Response.OutputStream.Write(buffer,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类似但不完全相同的问题。

正确的回答是什么?

正确的回答是整个资源。但是,由于此客户端包括一个Range标头,因此您可以206 Partial content和文件的子集进行响应。

我应该决定要响应的大小并坚持吗?

很大程度上取决于服务器的效率。请注意,就像在Firefox won't request further data after receiving 206 with specified content range中一样,您可能会遇到浏览器执行错误的操作。