您可以发布服务器发送的带有和不带有 PHP 脚本的标头吗?我想知道 PHP 脚本发送的 Content-Type 是否与正常提供文件不同。
在source 元素上指定type 属性也是一个好主意,这样浏览器就不必下载两个剪辑来确定是否可以播放它们。
我无法重现您的问题。我试图在 Safari 4.0.4 和当前的 WebKit 每晚使用following test page 重新创建问题。我只是使用 mod_rewrite 来根据参数而不是 PHP 分派到不同的格式,但我认为这不会产生影响,除非 PHP 以某种方式修改了文件。
<!DOCTYPE html>
<title>Auido test</title>
<audio controls autobuffer>
<source src="gnossienne-no-1?foo=bar&format=.mp4">
<source src="gnossienne-no-1?foo=bar&format=.ogg">
</audio>
你能试试我的例子,让我知道它是否适合你吗?
编辑啊。在仔细研究了一下之后,问题似乎是由于 Safari 中的 <audio> 元素在尝试确定内容大小时的行为方式很奇怪。
这是 Safari 在遇到指向直接从 Apache 提供的文件的 <audio> 元素时捕获的数据包的摘录。如您所见,它首先尝试获取媒体的前两个字节,大概是为了获取 Content-Length 以及可能的其他标头。然后它会尝试获取整个内容。然后,莫名其妙地,它再次尝试获取前两个字节,但传递适当的缓存标头以获得“304 Not Modified”响应。最后,仍然莫名其妙地,它再次获取文件的最后 3440 个字节。它在单独的 TCP 连接中完成所有这些工作,除了多次获取数据的开销之外,这会增加相当大的开销。
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1
主持人:ephemera.continuation.org
范围:字节=0-1
连接:关闭
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
接受: */*
接受编码:身份
饼干:[编辑]
HTTP/1.1 206 部分内容
日期:2010 年 1 月 5 日星期二 02:12:48 GMT
服务器:阿帕奇
最后修改时间:2010 年 1 月 5 日星期二 02:02:08 GMT
ETag:“b2a80ad-11f6-47c6139aaa800”
接受范围:字节
内容长度:2
内容范围:字节 0-1/4598
连接:关闭
内容类型:音频/mpeg
# 2字节数据
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1
主持人:ephemera.continuation.org
范围:字节=0-4597
连接:关闭
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
接受: */*
接受编码:身份
饼干:[编辑]
HTTP/1.1 206 部分内容
日期:2010 年 1 月 5 日星期二 02:12:48 GMT
服务器:阿帕奇
最后修改时间:2010 年 1 月 5 日星期二 02:02:08 GMT
ETag:“b2a80ad-11f6-47c6139aaa800”
接受范围:字节
内容长度:4598
内容范围:字节 0-4597/4598
连接:关闭
内容类型:音频/mpeg
# 4598字节数据
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1
主持人:ephemera.continuation.org
范围:字节=0-1
连接:关闭
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
接受: */*
接受编码:身份
饼干:[编辑]
如果无匹配:“b2a80ad-11f6-47c6139aaa800”
If-Modified-Since: 2010 年 1 月 5 日星期二 02:02:08 GMT
HTTP/1.1 304 未修改
日期:格林威治标准时间 2010 年 1 月 5 日星期二 02:12:49
服务器:阿帕奇
连接:关闭
ETag:“b2a80ad-11f6-47c6139aaa800”
# 没有数据
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1
主持人:ephemera.continuation.org
范围:字节=1158-4597
连接:关闭
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
接受: */*
接受编码:身份
饼干:[编辑]
HTTP/1.1 206 部分内容
日期:格林威治标准时间 2010 年 1 月 5 日星期二 02:12:49
服务器:阿帕奇
最后修改时间:2010 年 1 月 5 日星期二 02:02:08 GMT
ETag:“b2a80ad-11f6-47c6139aaa800”
接受范围:字节
内容长度:3440
内容范围:字节 1158-4597/4598
连接:关闭
内容类型:音频/mpeg
# 3440字节数据
无论如何,关于它如何处理 PHP 脚本的输出。在这里,Safari 再次尝试下载前两个字节,但您的脚本忽略了 Range 请求并返回整个内容。显然,WebKit 不喜欢这样,所以它再次尝试,没有Range 请求。同样,您的脚本会发送完整的内容。 Safari 现在再次尝试,添加一个Icy-Metadata 标头,这表明它认为它正在下载流并希望发送流元数据。它最终接受了它的输出,并且<audio> 元素可以播放。
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1
主持人:tts.mindtrove.info
范围:字节=0-1
连接:关闭
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
接受: */*
接受编码:身份
HTTP/1.1 200 正常
日期:格林威治标准时间 2010 年 1 月 5 日星期二 02:14:28
服务器:阿帕奇
X-Powered-By: PHP/5.2.10
内容长度:4598
连接:关闭
内容类型:音频/mpeg
# 4598字节数据
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1
主持人:tts.mindtrove.info
连接:关闭
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
接受: */*
HTTP/1.1 200 正常
日期:格林威治标准时间 2010 年 1 月 5 日星期二 02:14:28
服务器:阿帕奇
X-Powered-By: PHP/5.2.10
内容长度:4598
连接:关闭
内容类型:音频/mpeg
# 4598字节数据
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1
主持人:tts.mindtrove.info
接受: */*
用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
冰冷的元数据:1
连接:关闭
HTTP/1.1 200 正常
日期:格林威治标准时间 2010 年 1 月 5 日星期二 02:14:28
服务器:阿帕奇
X-Powered-By: PHP/5.2.10
内容长度:4598
连接:关闭
内容类型:音频/mpeg
# 4598字节数据
总而言之,Safari(或更准确地说,QuickTime,Safari 使用它来处理所有媒体和媒体下载)似乎有一种完全脑残的媒体下载方法。您发回数据的方式中的某些东西,可能是您没有响应Range 请求的事实,使它认为您正在发送流媒体,导致它重复下载内容(尽管即使面对服务器确实响应了Range 请求,但它仍然执行的请求比实际需要的请求多)。
我的建议是尝试对Range 的请求做出适当的回应;在提供媒体时,浏览器可能会使用它们来尝试最小化带宽,只缓冲它们需要能够播放的内容(尽管有 autobuffer 属性表示您希望它们缓冲整个内容,浏览器可能会忽略它)。我建议使用 X-Sendfile 让 Apache 处理提供文件、缓存和范围请求,但你似乎在 Dreamhost 上,它没有安装 mod_xsendfile,所以你将不得不滚动你的自己处理Range。