RangeFileContentResult和带有远程请求的视频流

dou*_*ald 13 c# asp.net-mvc-4 lib.web.mvc http-range

我有一个应用程序,旨在从我们的本地数据库流回视频.昨天我花了很多时间试图将数据返回成功RangeFileContentResultRangeFileStreamResult不成功.

简而言之,当我将文件作为这两个结果中的任何一个返回时,我似乎无法正确地传输视频(或者根本不播放).

来自浏览器的请求将通过以下标头发送:

Range: bytes=0-
Run Code Online (Sandbox Code Playgroud)

并且提供的响应以这些标头为例:

Accept-Ranges: bytes
Content-Range: bytes 0-5103295/5103296
Run Code Online (Sandbox Code Playgroud)

在网络流量方面,我获得了一系列206的部分结果,然后是200结尾(根据小提琴手),这似乎是正确的.Chrome的网络标签不同意这一点,并看到一个初始请求(总是13个字节,我假设是握手)然后是一些状态为已取消或待处理的请求.据我所知,这或多或少是正确的,206 - 取消,206 - 取消等.但视频永远不会播放.

如果我将结果从我的控制器切换到FileResult,视频播放和Chrome,IE10和Firefox似乎在下载完成之前开始播放(感觉有点像它的流媒体!虽然我怀疑它不是)

但是随着范围的结果,我在chrome或IE中得不到任何东西,整个视频在firefox中下载了一滴.

据我所知,RangeFileContentResult应该处理响应客户端的一系列字节要下载(我的似乎没有,它只是告诉它获取整个文件(由上面的响应说明)).客户应该对此做出回应,而这似乎并没有.

有没有人对这方面有任何想法?特别:

a)应该RangeFileContentResult将一系列字节发送回客户端吗?b)有没有办法可以明确控制客户端请求的字节范围?c)在请求时,是否有任何理由或错误导致浏览器根本不加载视频RangeFileContentResult

编辑:添加了一个图表,以帮助描述我所看到的:

RangedRequestImage

编辑2:好的,所以情节变浓了.在使用RangedFile gubbins的同时,我们需要推出另一个系统测试版本,并将"RangeFileContentResult"留在我的控制器操作上,如下所示:

private ActionResult RetrieveVideo(MediaItem media)
{
    return new RangeFileContentResult(
        media.Content, 
        media.MimeType, 
        media.Id.ToString(), 
        DateTime.Now);            
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这似乎在我们的Azure系统测试环境中按预期工作,但仍然不在我的本地计算机上.我想知道是否有一些基于IIS的东西在Azures IIS8上运行得很开心,但在我的本地7.5实例上却没有?

tpe*_*zek 5

这里描述的问题的原因是传递给构造函数的modificationDate参数的值RangeFileContentResult:

return new RangeFileContentResult(media.Content, media.MimeType, media.Id.ToString(), DateTime.Now); 
Run Code Online (Sandbox Code Playgroud)

此日期用于RangeFileResult创建两个标头:

  • ETag - 此标头是浏览器和服务器使用的标识符,用于确保它们正在谈论同一实体.
  • Last-Modified - 此标头通知浏览器实体的最后修改日期.

DateTime.Now每次浏览器发出部分请求时传递a的事实可能是在客户端获取整个实体之前更改ETagLast-Modified标头值的原因(通常如果整个过程花费的时间超过一秒).

在上述情况下,浏览器正在发送If-Range带有请求的标头.如果实体标记(或修改日期因为If-Range可以携带这两个值中的任何一个)并不多,则此标头告诉服务器应重新发送整个实体.在这种情况下会发生这种情况.

事实上,修改日期是"动态的"也可引起进一步的问题,如果客户决定使用以下标题之一验证:If-Modified-Since,If-Unmodified-Since,If-Match,If-None-Match.

在这种情况下的解决方案是在数据库中保留修改日期与文件,以确保它是一致的.

这里还有一个优化的地方.每次发出部分请求时,不是从DB抓取整个视频,而是可以缓存它或仅抓取相关部分(如果应用程序正在使用的数据库引擎允许这样的操作).可以使用这种机制以通过传递RangeFileResult和覆盖WriteEntireEntity以及WriteEntityRange方法来创建专门的动作结果.