Yihui Xie

得意程序侦查一则:傲娇的 Safari 不能播放 MP4

谢益辉 / 2017-04-13


有客官留言说动画网站里的 MP4 动画在 Safari 浏览器上不能播放,于是我花了几个小时侦查这个问题。凡是网页问题的侦查,一律都是从浏览器的开发者工具开始看起,看看 HTML/CSS 源代码、网络资源的请求和下载状况、JS 控制台等等。

我发现 Safari 里 MP4 的请求出错,于是找来一个示例 MP4 文件,结果示例文件可以播放,细看了一下区别,浏览器发送的是特殊的区域请求(range request),根据这个请求,示例文件的服务器返回了被请求的文件区域。所谓区域,也就是文件的一部分内容,比如从第 100 到 125 字节。这在视频文件的请求中比较常见,通常网页里的文件都是一口气下载,但视频文件由于通常比较大,不一定需要一口气下载完,所以视情况一段一段下载,比如用户拖到哪儿就从哪儿下载起,免得浪费带宽。

我的 MP4 文件不能播放的原因是区域请求没有返回正确的内容,应该返回的有这么几样东西:

  1. 状态码 206(表示成功);

  2. 请求的字节内容;

  3. 头信息 Content-Range,里面注明返回的字节所属的区域(从几到几)以及文件的总字节数;

但这个问题实际上是两个问题。我用 servr 包创建的本地服务器在 Safari 中不能播放 MP4,我放在 Updog 上的远程 MP4 文件也不能播放。首先我看了一下 servr 包的问题,发现是因为上面的信息 3 没有正确返回,于是把它加上了,同时我还发现以前的代码实现里有一个难以察觉的错误,返回的字节数少了 1 位1。本地预览 animation 网站没问题了,而且这还顺带解决了困扰我长达三年之久的 RStudio 问题,就是上次说的 RStudio Viewer 里无法预览 MP4 动画的问题,通过这么一改,现在在苹果系统上的 RStudio 里可以直接看 MP4 了(别的系统也许还不行)。

然后 Updog 的问题类似,它不知道怎么响应区域请求,只能一口气返回一整个文件。向网站负责人反馈了一下,解决方案是在 MP4 文件链接后面加上 ?dl=1 参数。

于是现在傲娇的 Safari 也可以播放 animation 包生产的 MP4 动画了。别的浏览器就不在乎这个(就算不能返回 206 状态也无所谓),不知道 Safari 为什么要这么严格。


  1. 数数从 0 开始还是从 1 开始这种分歧真是害死人,很容易发生这种多 1 个少 1 个的问题。