您是否可以使用和不使用PHP脚本发布服务器发送的标头?我想知道PHP脚本是否发送了不同的内容 Content-Type 比正常提供文件。
Content-Type
指定它也是一个好主意 type 属性 source 元素,因此浏览器不必下载两个剪辑来确定它是否可以播放它们。
type
source
我无法重现你的问题。我试图在Safari 4.0.4和当前的WebKit中重新创建问题 以下测试页面 。我只是使用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>
你可以尝试我的例子,让我知道它是否适合你?
的 编辑 强> 啊。在稍微探讨一下之后,似乎问题是由于一种奇怪的方式 <audio> Safari中的元素用于尝试确定内容的大小。
<audio>
这是Safari遇到一个数据包捕获的摘录 <audio> 指向直接从Apache提供的文件的元素。正如您所看到的,它首先尝试获取媒体的前两个字节,可能是因为它可以返回Content-Length,可能还有其他标头。然后它试图获取整个事物。然后,莫名其妙地,它尝试再次获取前两个字节,但传递适当的缓存头以获得“304 Not Modified”响应。最后,仍然莫名其妙地,它再次获取文件的最后3440个字节。它在单独的TCP连接中完成所有这些操作,除了几次获取数据的开销之外,还会增加相当大的开销。
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=0-1 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] HTTP/1.1 206 Partial Content Date: Tue, 05 Jan 2010 02:12:48 GMT Server: Apache Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT ETag: "b2a80ad-11f6-47c6139aaa800" Accept-Ranges: bytes Content-Length: 2 Content-Range: bytes 0-1/4598 Connection: close Content-Type: audio/mpeg # 2 bytes of data GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=0-4597 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] HTTP/1.1 206 Partial Content Date: Tue, 05 Jan 2010 02:12:48 GMT Server: Apache Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT ETag: "b2a80ad-11f6-47c6139aaa800" Accept-Ranges: bytes Content-Length: 4598 Content-Range: bytes 0-4597/4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=0-1 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] If-None-Match: "b2a80ad-11f6-47c6139aaa800" If-Modified-Since: Tue, 05 Jan 2010 02:02:08 GMT HTTP/1.1 304 Not Modified Date: Tue, 05 Jan 2010 02:12:49 GMT Server: Apache Connection: close ETag: "b2a80ad-11f6-47c6139aaa800" # no data GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 Host: ephemera.continuation.org Range: bytes=1158-4597 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity Cookie: [redacted] HTTP/1.1 206 Partial Content Date: Tue, 05 Jan 2010 02:12:49 GMT Server: Apache Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT ETag: "b2a80ad-11f6-47c6139aaa800" Accept-Ranges: bytes Content-Length: 3440 Content-Range: bytes 1158-4597/4598 Connection: close Content-Type: audio/mpeg # 3440 bytes of data
无论如何,关于如何处理PHP脚本的输出。在这里,Safari再次尝试下载前两个字节,但是你的脚本忽略了 Range 请求并返回整个事情。显然,WebKit不喜欢这样,所以它再次尝试,没有 Range 请求。同样,您的脚本会发送完整的内容。 Safari现在再次尝试,添加一个 Icy-Metadata 标头,表示它认为它正在下载流并希望发送流式元数据。它最终接受了那个的输出,并且 <audio> 元素可以玩。
Range
Icy-Metadata
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 Host: tts.mindtrove.info Range: bytes=0-1 Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* Accept-Encoding: identity HTTP/1.1 200 OK Date: Tue, 05 Jan 2010 02:14:28 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 Host: tts.mindtrove.info Connection: close User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Accept: */* HTTP/1.1 200 OK Date: Tue, 05 Jan 2010 02:14:28 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 Host: tts.mindtrove.info Accept: */* User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 Icy-Metadata: 1 Connection: close HTTP/1.1 200 OK Date: Tue, 05 Jan 2010 02:14:28 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 4598 Connection: close Content-Type: audio/mpeg # 4598 bytes of data
总而言之,Safari(或者更确切地说,Safari用于处理所有媒体和媒体下载的QuickTime)似乎有一种完全受到严重影响的下载媒体方法。您发送数据的方式可能是您没有回复的事实 Range 请求,让它认为您正在发送流媒体,导致它重复下载内容(尽管即使遇到响应a的服务器) Range 请求,它仍然会提出比实际需要更多的请求)。
我的建议是尽量适当回应 Range 要求;在提供媒体时,浏览器可能会使用它们来尝试最小化带宽,只需缓冲它们需要能够播放的内容(尽管有 autobuffer 属性表示你希望它们缓冲整个事物,浏览器可能会忽略它)。我建议使用 X-Sendfile 让Apache处理文件,缓存和范围请求的服务,但你似乎是在没有的Dreamhost上 mod_xsendfile 安装,所以你将不得不自己动手 Range 处理。
autobuffer
X-Sendfile
mod_xsendfile
我遇到了同样的问题。 关键是 的 内容范围 强> 头。 将它添加到mp3输出php后,一切正常。
为了记录,虽然Pochang和Chris都是正确的,你需要Content-Range标头来解决Safari中的这个问题,Chrome需要一个额外的标头,必须包含这些标头才能使currentTime正常工作:
header( 'Accept-Ranges: bytes');
请注意,您实际上不必正确响应请求的Range标头,您只需将其包含在响应中即可。
Pochang是正确的。在PHP响应中包含Content-Range标头将导致Safari正常运行。它还允许在Safari中搜索(media.currentTime = 0;)而不使用可怕的INDEX_SIZE_ERR,但不在Chrome中。
标头的PHP代码是:
$len = strlen( $data ); $shortlen = $len - 1; header( 'Content-Range: bytes 0-'.$shortlen.'/'.$len);