问题的背景我正在使用jPlayer在ZF2应用程序中播放一些音频文件。jPlayer使用ZF2操作作为音频源,效果良好。通过控制器操作,我使用response对象发回一个原始响应。简化的代码如下所示:
public function streamAction()
{
// ... left out code to retrieve order and error handling stuff ... //
$response = $this->getResponse();
$path = $this->orderService->getFullPathToAudioFile($order);
$response->setStatusCode(Response::STATUS_CODE_200);
$response->getHeaders()->addHeaderLine('Content-Type', 'audio/mpeg')
->addHeaderLine('Content-Length', filesize($path))
->addHeaderLine('Expires', -1)
->addHeaderLine('Cache-Control', 'no-store, no-cache, must-revalidate');
$response->setContent(readfile($path));
return $response;
}
在Chrome中,jPlayer的HTML5实现将其用作音频源没有问题。Firefox自动恢复了jPlayer的Flash实现,并且运行良好。Safari也使用HTML5实现,但有一个问题,但当我使用jPlayer的Flash实现时,效果很好。
这促使我研究响应中实际发送回的标头。我用萤火虫检查了一下。我在这里注意到了一些奇怪的事情:Content-Length标头没有被发回,Content-Type是"text/html",而不是我指定的"audio/mpeg"。
测试代码我做了一个小测试动作来演示:
public function testAction()
{
$path = './data/audio/test.mp3';
$response = $this->getResponse();
$response->setStatusCode(Response::STATUS_CODE_200);
$response->getHeaders()->addHeaderLine('Content-Type', 'audio/mpeg')
->addHeaderLine('Content-Length', filesize($path))
->addHeaderLine('Expires', -1)
->addHeaderLine('Cache-Control', 'no-store, no-cache, must-revalidate');
$response->setContent(readfile($path));
return $response;
}
请注意我验证了可以找到音频文件。当我在浏览器中调用测试操作时,我也可以看到这一点。它显示mp3文件的内容。
情节变厚当我评论设置内容的行时:$response->setContent(readfile($path));我确实在响应中看到了正确的Content-Type标头和Content-Length标头。
此外,当我创建一个像下面这样的简单纯文本响应时,它也能正常工作。
public function testAction()
{
$response = $this->getResponse();
$response->setStatusCode(Response::STATUS_CODE_200);
$response->getHeaders()->addHeaderLine('Content-Type', 'text/plain')
->addHeaderLine('Content-Length', 10)
->addHeaderLine('Expires', -1)
->addHeaderLine('Cache-Control', 'no-store, no-cache, must-revalidate');
$response->setContent('0123456789');
return $response;
}
有什么想法吗?为什么会这样,我该如何解决它?
您的代码的主要问题是readfile()
不会返回文件内容,而是立即将其输出到浏览器。因此,您对响应对象所做的更改没有任何效果,因为没有使用响应对象。如果您将其更改为file_get_contents()
,它可能会如您所期望的那样工作。
除非您正在流式传输的文件很小(<10KB),否则我建议您查看XSendFile,它将以一种更节省内存的方式完成所有这些操作,并自动为您处理标头(包括范围标头,这将使人们跳过曲目)。