Laravel 4.2提供mp3 - 不可风

时间:2015-09-27 09:38:52

标签: php laravel audio laravel-4 httpresponse

我在使用Laravel 4.2提供mp3时遇到了一些问题 我有一些应该由flashplayer播放的文件。

    public function get($filename)
    {
        $file = new Symfony\Component\HttpFoundation\File\File(storage_path().DbConfig::get('system.upload_dir').'/'.DbConfig::get('system.upload_music').'/'.$filename);

        $response =  Response::make(file_get_contents(storage_path().DbConfig::get('system.upload_dir').'/'.DbConfig::get('system.upload_music').'/'.$filename));
        $response->header('Content-Type', $file->getMimeType());
        $response->header('Content-Length', $file->getSize());
        $response->header('Content-Transfer-Encoding', '');
        $response->header('Accept-Range', 'bytes');
        $response->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
        $response->header('Connection', 'Keep-Alive');
        return $response;
    }

这为文件提供服务 - 如果在Chrome中打开它会弹出chrome的默认播放器并播放音乐,同样的事情就是当我用flashplayer对它进行观看时。

但是我无法记录。 如果我用apache(而不是Laravel控制器)提供文件,它可以正常工作。

如果有人能帮我解决这个问题,我将不胜感激。

更新

通过Laravel服务的标题:

HTTP/1.1 200 OK
Date: Thu, 01 Oct 2015 18:43:59 GMT
Server: Apache/2
Cache-Control: must-revalidate, post-check=0, pre-check=0, private
Content-Transfer-Encoding: 
Accept-Range: bytes
Connection: Keep-Alive, Keep-Alive
Set-Cookie: laravel_session=eyJ[...]D; expires=Thu, 01-Oct-2015 20:44:00 GMT; Max-Age=7200; path=/; httponly
Vary: Accept-Encoding,User-Agent
Keep-Alive: timeout=2, max=100
Transfer-Encoding: chunked
Content-Type: audio/mpeg

没有Laravel时提供的标题:

HTTP/1.1 200 OK
Date: Thu, 01 Oct 2015 18:51:16 GMT
Server: Apache/2
Last-Modified: Fri, 13 Mar 2015 04:03:23 GMT
ETag: "ead61-5112394e338c0"
Accept-Ranges: bytes
Content-Length: 961889
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: audio/mpeg

1 个答案:

答案 0 :(得分:1)

标题的主要区别在于使用Laravel时缺少Content-Length。我不知道flash播放器是如何工作的,但我冒昧地需要知道文件的长度能够寻找(即风)到任何位置。

但是,您发布的代码会明确设置该标头。搜索了一下,我发现了这个Laravel问题:2079。他们建议使用未记录的Response::stream来发送文件内容,如下所示:

Response::stream(function() use($fileContent) { echo $fileContent; }, 200, $headers);

这里是Symfony doc for StreamedResponse

响应类型更新

您正在提供静态文件,因此要使用的相应响应类型是BinaryFileResponse到Laravel' Response::download($pathToFile, $name, $headers)

(顺便说一句,您可以使用第三个参数来设置标题)

内容长度更新

Symfony's Response类的来源是Content-Length被删除的关键:

/**
 * Prepares the Response before it is sent to the client.
 *
 * This method tweaks the Response to ensure that it is
 * compliant with RFC 2616. Most of the changes are based on
 * the Request that is "associated" with this Response.
 *
 * @param Request $request A Request instance
 *
 * @return Response The current response.
 */
public function prepare(Request $request)
{
    $headers = $this->headers;
    if ($this->isInformational() || $this->isEmpty()) {
        // [snip]
    } else {
        // [snip]
        // Fix Content-Length
        if ($headers->has('Transfer-Encoding')) {
            $headers->remove('Content-Length');
        }
        // [snip]
    }
    // [snip]
}

RFC 2616不允许使用Transfer-EncodingContent-Length标头,Symfony会强制执行此操作。引用:

  

4.4消息长度

     

[...]

     

3.如果存在Content-Length头字段(第14.13节),则为        OCTET中的十进制值表示实体长度和        转发长度。不得发送Content-Length头字段        如果这两个长度不同(即,如果转移编码        标题字段存在)。如果收到包含a的消息        Transfer-Encoding标头字段和Content-Length标头字段,        后者必须被忽略。

此外,根据此SO questionContent-Transfer-Encoding仅用于电子邮件。否则使用Transfer-Encoding

另一件事:你在Laravel中使用了Accept-Range而在Apache中使用了Accept-Ranges

最后,尝试一个简单的download响应,而不设置任何标题,看看你得到了什么。然后根据需要添加更多标题。