Laravel 4.2 服务 mp3 - 不可缠绕

Posted

技术标签:

【中文标题】Laravel 4.2 服务 mp3 - 不可缠绕【英文标题】:Laravel 4.2 serving mp3 - not windable 【发布时间】:2015-12-24 17:19:38 【问题描述】:

我在使用 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

【问题讨论】:

在这种情况下,“风”是什么意思?我建议您记录您在 Apache 和 Laravel 中收到的响应标头并将它们发布在这里,以便我们可以看到有什么不同。 @bernie 看看我的更新,“wind”表示我可以使用播放器栏跳过记录的某些部分,稍后我可以将其倒回到开头。 【参考方案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 标头字段 如果这两个长度不同(即,如果传输编码 头字段存在)。如果同时收到一条消息 Transfer-Encoding 头域和一个 Content-Length 头域, 后者必须被忽略。

另外,根据SO question,Content-Transfer-Encoding 仅用于电子邮件。否则使用Transfer-Encoding

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

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

【讨论】:

即使我使用 Response::stream 我无法设置 Content-Length 标头 - 我可以设置 Some-Dummy-Header 并且它存在于响应标头中,但 Laravel 不允许我设置内容-长度:/ 我昨天整天都在与这个问题作斗争,但什么也没有 - 我尝试了所有类型的回复 makedownloadstream,但什么也没有 - 我无法设置 Content-Length的响应,所以我不得不做一些解决方法来实现我想要的(几乎)同时访问 mp3 和 Laravel 模型。我不得不将文件从 storage 移动到 public 目录并重定向到它(使用 apache 服务)在访问它的模型后。无论如何感谢您的回答 - 它帮助我理解了这个问题。

以上是关于Laravel 4.2 服务 mp3 - 不可缠绕的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4.2 Route HTTPS 在服务器上不起作用

Laravel 4.2 应用程序在上传实时服务器后发生不必要的重定向

Composer - Forked Laravel 4.2 未安装

Laravel 4.2 根据请求频率生成新的 CSRF 令牌?

Laravel 4.2 artisan CLI 在作曲家更新后不再工作

Laravel 4.2 AWS SQS 队列设置使用 EB 工作环境