【发布时间】:2021-09-15 04:07:00
【问题描述】:
我遇到了一个奇怪的问题,不知道接下来的调试步骤。我希望社区可以提出一些想法。
我正在使用以下堆栈:
PHP 7.2.34-21+ubuntu16.04.1+deb.sury.org+1 (fpm-fcgi) (built: May 1 2021 11:52:36)
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.34-21+ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
Server version: Apache/2.4.39 (Ubuntu)
Wordpress 4.9.16
在 AWS 服务上。显然,由于框架存在一些开销,但我可以将代码简化为以下内容:
// Framework stuff + file handling logic
$data = 'Imagine this is a 1000-byte binary message (pdf).';
// Headers, 335 bytes large
header('date: Sat, 03 Jul 2021 05:06:41 GMT');
header('server: Apache/2.4');
header('expires: Wed, 11 Jan 1984 05:00:00 GMT');
header('cache-control: no-cache, must-revalidate, max-age=0');
header('content-disposition: inline; filename=window-sticker.pdf');
header('strict-transport-security: max-age=1209600;');
header('content-length: 1000'); // Actually use strlen($data); for this
header('x-ua-compatible: IE=edge');
header('cache-control: public');
header('content-type: application/pdf');
echo $data;
exit();
现在这是踢球者。这在许多其他站点上运行良好,据我所知,使用相同的 apache sites-enabled 配置和类似的 .htaccess 文件。但它可能仍然是服务器/网络/等。类型错误,所以我可能会遗漏一些东西。
我有这个网站,但是,此代码以下列方式中断:
- 不强制执行
content-length的工具可以完美地下载/显示此内容(例如chrome)。 - 跟踪
content-length的工具会失败或发出通知(safari、curl)。卷曲给了我:
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7ff13c008200)
> GET /redacted/path/to/controller?p=abcdef HTTP/2
> Host: www.redacted-somesite.com
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0< HTTP/2 200
< date: Sun, 04 Jul 2021 17:36:24 GMT
< server: Apache/2.4
< expires: Wed, 11 Jan 1984 05:00:00 GMT
< cache-control: no-cache, must-revalidate, max-age=0
< content-disposition: inline; filename=window-sticker.pdf
< strict-transport-security: max-age=1209600;
< content-length: 1000
< x-ua-compatible: IE=edge
< cache-control: public
< content-type: application/pdf
<
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!
0 1000 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0
* Connection #0 to host www.redacted-somesite.com left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* Closing connection 0
我检查过的东西:
- 内容长度IS设置正确,正文与该标头中设置的大小相同。
- 数据 IS 正在输出,因为 chrome 等工具可以获取完整文件
- 删除
content-length标头可以在所有工具中使用。
现在,我不确定为什么事情会失败。我目前的理论是,不知何故,对于这个站点,一些静默错误可能会在标头发出之前写入缓冲区。但是当我用十六进制工具检查从服务器发送的二进制数据时,它是完全匹配的。所以我很茫然。也许有一些压缩层在搞我?
任何想法都会很棒。
谢谢!
【问题讨论】:
-
这能回答你的问题吗? HTTP Headers for File Downloads
-
@Top-Master 不是真的。我确实想在浏览器中显示它,并且我已经包含了
content-type和content-disposition标题。 -
您正在使用的确切 Apache 版本是什么,包括 fpm 模块以及正在使用的确切 php-fpm 版本(php 版本)是什么[对于您遇到问题的服务器]?这看起来像是软件不兼容/配置错误。 conent-length 应该定义明确。我假设分块传输没有起作用(你清楚地写了标题大小被考虑在内,是的,它不应该)。使用 wireshark 或类似工具在传输层进行验证。
-
我总是在发送标头之后和发送有效负载之前使用 ob_clean() 清除输出缓冲区,它往往会消除很多像这样的奇怪问题。这有点像货物崇拜,但在深入兔子洞之前先试一试。
-
你能在命令行上试试 curl 吗?它有很好的
-v开关,因此它显示请求和响应标头(与-i结合),管道进入输出文件,然后它显示确切的字节,并且写入的字节也可以通过输出文件的大小看到.