[廚餘回收] ASP.NET MVC 5 回傳 video/mp4 在 Google Chrome 播放時無法跳轉

我們偶爾需要使用 ASP.NET MVC 5 的 Action 回傳一個 FilePathResult,今天一如往常地我回傳一個 FilePathResult,contentType 是 video/mp4,可是在 Google Chrome 卻無法跳轉,變這樣…

原本單純的寫法

使用 MVC 自帶的 File 多載方法回傳一個 FilePathResult,contentType 打上 video/mp4。

public ActionResult GetVideo()
{
    return File(@"D:\9490c478-35e3-4c27-8a19-ddc9b31e7c20.mp4", "video/mp4");
}

使用 HTML5 的 video 來呈現並播放。

<video controls>
    <source src="http://localhost:20870/Home/GetVideo" type="video/mp4" />
</video>

結果就像上面那張圖一樣,可是如果我們直接把 src 指定為一個靜態的 mp4 檔時,就可以跳轉了,為何有如此差異,這其中必有緣故。

加入 Last-Modified、Accept-Ranges 這兩個 Headers

這時候 Fiddler 就是我們的好朋友了,來比較靜態 mp4 檔跟我們的 FilePathResult 所收到的 HTTP Response 有何不同?

首先是 FilePathResult 的 Response Headers

再來是靜態 mp4 檔的 Response Headers

經過我身為程式設計師的直覺判斷,問題出在這兩個 Header:Last-ModifiedAccept-Ranges,所以我們依樣畫葫蘆給入這兩個 Header 及其值。

public ActionResult GetVideo()
{
    var file = new FileInfo(@"D:\9490c478-35e3-4c27-8a19-ddc9b31e7c20.mp4");

    Response.Headers.Add("Last-Modified", file.LastWriteTime.ToUniversalTime().ToString("R"));
    Response.Headers.Add("Accept-Ranges", "bytes");

    return File(@"D:\9490c478-35e3-4c27-8a19-ddc9b31e7c20.mp4", "video/mp4");
}

哈哈,猜得沒錯,可以跳轉了。

或者可以使用 Lib.Web.MVC

另外,跟我的同事反應這個問題之後,他則找到一個 Lib.Web.MVC 套件,來解決這個問題。

從 NuGet 上安裝 Lib.Web.MVC 套件,將原本回傳 FilePathResult 改回傳 RangeFilePathResult 就可以了。

public ActionResult GetVideo()
{
    var file = new FileInfo(@"D:\9490c478-35e3-4c27-8a19-ddc9b31e7c20.mp4");

    return new RangeFilePathResult("video/mp4", file.FullName, file.LastWriteTime, file.Length);
}

不過,使用 RangeFilePathResult 所收到的 HTTP Response Headers 不太一樣。

它是 response HTTP 206 而不是 HTTP 200,查維基得到這樣的說明。

206 Partial Content
伺服器已經成功處理了部分GET請求。
類似於FlashGet或者迅雷這類的HTTP 下載工具都是使用此類響應實作斷點續傳或者將一個大文件分解為多個下載段同時下載。

看起來,用 Lib.Web.MVC 好像好一點。

參考資料

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學