---
title: 得意程序侦查一则：傲娇的 Safari 不能播放 MP4
date: '2017-04-13'
slug: safari-mp4
---

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

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

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

1. 状态码 206（表示成功）；

1. 请求的字节内容；

1. 头信息 `Content-Range`，里面注明返回的字节所属的区域（从几到几）以及文件的总字节数；

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

然后 Updog 的问题类似，它不知道怎么响应区域请求，只能一口气返回一整个文件。向网站负责人反馈了一下，[解决方案](https://github.com/yihui/yihui.org/commit/d2cf99e3)是在 MP4 文件链接后面加上 `?dl=1` 参数。

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

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