简体   繁体   English

传输编码:分块和 MP3/Lame

[英]Transfer-encoding: chunked and MP3/Lame

I have a PHP webservice that returns an mp3 HTTP response.我有一个返回 mp3 HTTP 响应的 PHP 网络服务。 It works, but when I turn on Chrome's network throttling in DevTools, it returns only part of the response:它有效,但是当我在 DevTools 中打开 Chrome 的网络节流时,它只返回部分响应:

        $stream_start1 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start2 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start3 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start4 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start5 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start6 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start7 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start8 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start9 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start10 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start11 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start12 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));
        $stream_start13 = Psr7\stream_for(fopen('./sounds/ping.mp3', 'r'));

        return new Psr7\AppendStream([$stream_start1 , $stream_start2 , $stream_start3 , $stream_start4 , $stream_start5 , $stream_start6 , $stream_start7 , $stream_start8 , $stream_start9 , $stream_start10, $stream_start11, $stream_start12, $stream_start13]);

With the above code, with dev throttling on, I am getting back 7 pings instead of 13.使用上面的代码,在开发节流的情况下,我得到了 7 个 ping 而不是 13 个。

In reality the real code is getting a stream from a 3rd party service and and sandwiching it between two files:实际上,真正的代码是从 3rd 方服务获取流并将其夹在两个文件之间:

 return new Psr7\AppendStream([file1Stream, 3rdPartyStream, file2Stream])

So, I don't necessarily know the length in order to set Content-Length, and so it's using Transfer-Encoding: chunked.所以,我不一定知道设置内容长度的长度,所以它使用传输编码:分块。

When I look in dev tools at the shortened responses of the requests, I consistently see them ending around what looks like some LAME metadata or added silence:当我在开发工具中查看请求的缩短响应时,我始终看到它们以看起来像一些 LAME 元数据或添加的静音结束:

e¨Deš•†š¹‡ÌC`̹3†'2 CBR9S¨Âöe­i´g¡ÿ–W©^¥ÔzWI}I8¸¶vv,¸¼Ù£J*ÙÙû±W•'X&+X±£@È ·bbÂìýbŸâÿâŸëLAME3.100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUÿóbÄ”AIÖtUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU

What I'm wondering is if it's possible that the browser is confusing some of this LAME info (or something else) for the end of the chunk sequence due to delays in receiving chunks.我想知道的是,由于接收块的延迟,浏览器是否有可能在块序列的末尾混淆了某些 LAME 信息(或其他信息)。 Is it possible that mixed up in the audio binary is something resembling an "empty chunk" indicating a last chunk?音频二进制文件中的混合是否有可能类似于指示最后一个块的“空块”? Is there a way to "escape" or encode the data to avoid potential sequences like this?有没有办法“转义”或编码数据以避免这样的潜在序列? Through compression, maybe?通过压缩,也许?

My other option is to read the 3rd party stream (in the middle of the sandwich) all the way into memory before forwarding it.我的另一个选择是在转发之前将第 3 方流(在三明治中间)一直读入内存。 That way I can calculate the length and set the Content-Length, so that's plan B.这样我就可以计算长度并设置内容长度,所以这就是 B 计划。

UPDATE: I have tried setting Content-Length on my little 13-file example there but I still get 7 pings as a response.更新:我尝试在我的 13 文件小示例上设置 Content-Length,但我仍然收到 7 个 ping 作为响应。 The length I've calculated with:我计算的长度:

$length = strlen($stream_start0->getContents()) * 13 

Which is 122252. But the file content that is returned is around 65529 bytes long (hex editor says 65536...?).这是 122252。但返回的文件内容大约有 65529 字节长(十六进制编辑器说 65536...?)。 Anyway, it's too short.总之,太短了。 Also, the Transfer-Encoding header is gone, which means I guess it's not being chunked anymore?此外,Transfer-Encoding 标头消失了,这意味着我猜它不再被分块了?

UPDATE2: It's also possible the problem is that I am concatenating mp3 files raw. UPDATE2: 问题也可能是我正在连接原始的 mp3 文件。 I think technically things get shady when you do that, especially if the audio contains ID3 tags and such, though in the ping files used above, there shouldn't be any ID3 tags.我认为从技术上讲,当您这样做时,事情会变得阴暗,特别是如果音频包含 ID3 标签等,尽管在上面使用的 ping 文件中,不应该有任何 ID3 标签。 However, in our stg environment where I observe this issue w/o dev tools, the cutoffs don't always happen on the breaks between files.然而,在我们的 stg 环境中,我在没有开发工具的情况下观察到这个问题,截止并不总是发生在文件之间的中断处。

So all of the above was a red herring.所以以上所有都是红鲱鱼。 It turned out the problem was I copied some blog post with JavaScript code that was calling response.getReader().read() only once, and thus only getting the first chunk of the response.结果发现问题是我用 JavaScript 代码复制了一些博客文章,这些代码只调用了response.getReader().read()一次,因此只获得了响应的第一块。

Apparently it's meant to be invoked in a loop until the end of the stream is reached like most stream APIs, but I missed it.显然,它应该像大多数流 API 一样在循环中调用,直到到达流的末尾,但我错过了它。

The solution was using response.blob() , which reads to the end of the stream and creates the Blob I need in one go.解决方案是使用response.blob() ,它读取到流的末尾并一次性创建我需要的 Blob。

I thought I had validated everything I copied, but I guess not.我以为我已经验证了我复制的所有内容,但我想没有。 But I learned a few things, so there's that.但我学到了一些东西,所以就是这样。

Docs on reader.read() reader.read() 上的文档
Docs on response.blob() 关于 response.blob() 的文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM