Transfer-encoding:分块和 MP3/Lame

Transfer-encoding: chunked and MP3/Lame

我有一个 PHP 网络服务,returns 一个 mp3 HTTP 响应。它有效,但是当我在 DevTools 中打开 Chrome 的网络节流时,它 returns 只是响应的一部分:

        $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]);

使用上面的代码,在打开开发节流的情况下,我得到了 7 个 ping 而不是 13 个。

实际上,真正的代码是从第 3 方服务获取流并将其夹在两个文件之间:

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

所以,我不一定知道长度才能设置 Content-Length,所以它使用 Transfer-Encoding: chunked.

当我在开发工具中查看请求的缩短响应时,我始终看到它们以看起来像一些 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

我想知道的是,是否有可能由于接收块的延迟,浏览器将一些 LAME 信息(或其他信息)混淆为块序列的末尾。是否有可能在音频二进制文件中混合了类似于表示最后一个块的“空块”的东西?有没有办法“转义”或编码数据以避免这样的潜在序列?也许是通过压缩?

我的另一个选择是在转发之前将第 3 方流(在三明治中间)一直读入内存。这样我就可以计算长度并设置 Content-Length,这就是计划 B.

更新: 我已经尝试在我的 13 文件小示例中设置 Content-Length,但我仍然收到 7 个 ping 作为响应。我计算的长度:

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

这是 122252。但是返回的文件内容大约有 65529 字节长(十六进制编辑器说 65536...?)。总之就是太短了。另外,Transfer-Encoding header 不见了,这意味着我猜它不再被分块了?

更新 2: 问题也可能是我正在连接原始的 mp3 文件。我认为从技术上讲,当您这样做时,事情会变得可疑,特别是如果音频包含 ID3 标签等,尽管在上面使用的 ping 文件中,不应该有任何 ID3 标签。然而,在我观察到这个问题的 stg 环境中 w/o 开发工具,中断并不总是发生在文件之间的中断处。

所以以上都是转移注意力的问题。原来问题是我用 JavaScript 代码复制了一些博客 post 只调用了 response.getReader().read() 一次,因此只得到了响应的第一块。

显然它应该像大多数流 API 一样在循环中调用,直到到达流的末尾,但我错过了它。

解决方案是使用 response.blob(),它读取到流的末尾并一次性创建我需要的 Blob。

我以为我已经验证了我复制的所有内容,但我想不是。但是我学到了一些东西,就是这样。

Docs on reader.read()
Docs on response.blob()