POST 使用分块编码对 PHP7 的请求不正确 return 结果
POST request to PHP7 with chunked encoding does not properly return result
我正在从客户端发送 POST 请求(使用 curl
和自定义 nodejs 脚本进行测试),但没有正确返回响应。 PHP 5.6.
一切正常
环境
整个事情尽量减少:
- Vagrant VM 中的所有内容 运行 Ubuntu 14.04 LTS
- nginx 1.9.7 来自 http://nginx.org/packages/ubuntu/
- PHP7 FPM 编译自官方来源
--disable-all --enable-fpm
我正在使用的最小 nginx 站点配置:
server {
listen 80;
server_name localhost;
location / {
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_pass unix:/var/run/php/php7.0-fpm-api.sock;
fastcgi_param SCRIPT_FILENAME /vagrant/index.php;
}
}
示例 PHP 来自 /vagrant/index.php
的脚本:
<?php
echo str_repeat('.', 512);
flush(); // not necessary, only due testing
我正在使用的 curl 调用:curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
我正在使用的 NodeJS 脚本:
'use strict';
var http = require('http');
var url = require('url');
var uri = url.parse(process.env.URL);
var options = {
method: 'POST', protocol: uri.protocol, hostname: uri.hostname,
port: uri.port, path: uri.path,
};
var data = '';
var httpRequest = http.request(options, function(res) {
res.on('data', function(chunk) {
console.log('received data', chunk.length);
data += chunk;
});
res.on('end', function() { console.log('final size', data.length); });
})
.on('error', function(err) { console.log(err); });
httpRequest.write('');
httpRequest.end();
正在将我的测试请求发送到 PHP 5.6
$ curl http://localhost/
..........[cut off]
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
..........[cut off]
$ URL=http://localhost/ node php7test.js
received data 512
final size 512
正在将我的测试请求发送到 PHP 7.0
$ curl http://localhost/
..........[cut off]
$ URL=http://localhost/ node php7test.js
final size 0
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
curl: (18) transfer closed with outstanding read data remaining
为什么我要乱用分块编码?
没有商业理由这样做,但是我使用了一个非常相似的 NodeJS 代码,默认为分块编码,切换到 PHP7 时突然停止工作。
我发现以下内容可以从 nodejs 端工作:显式设置 Content-Length
header 删除由 NodeJS 发送的隐式 Transfer-Encoding: chunked
header 并因此工作两个 PHP 版本。
但是我想了解为什么 PHP7 在这里表现不同,以及我是否有误或者这里到底发生了什么。
更新一:
- 我比较了 5.6 和 7.0 之间的
sapi/fpm/
来源,除了由于 PHP 内部变化 引起的变化外,我几乎看不出任何区别
- built-in服务器(
php -S
)不受影响,所有测试
更新二:
我将 PHP 来源一分为二,并且能够查明行为发生变化的时间:
- 我能够编译的最后一次提交:
https://github.com/php/php-src/commit/16265a59ac6bd433bfb636e4e44da1ad57cdcda9
- 第一次提交我能够再次编译但没有用:https://github.com/php/php-src/commit/86de98cabada88f4667839794c176ea37648498b
在两者之间,git bisect
的输出,我无法编译的提交:
$ git bisect skip
There are only 'skip'ped commits left to test.
The first bad commit could be any of:
ba5ecf355fe792a5a2a8e6582d5e081d02b16fbf
e383cb4493031a7cd952cfcaed3297e583149c07
fef18f4bea1980a59a9283c2197bd090aaf500cb
18cf4e0a8a574034f60f4d123407c173e57e54ec
We cannot bisect more!
感觉这可能是一个错误,我将其写给内部人员,也许他们有一些见解:https://marc.info/?l=php-internals&m=145090900217798&w=2
从你的 post 我猜你正在使用 PHP7.0.0。如果我的猜测是 (bool) TRUE 那么我建议你迁移到 PHP7.0.1.
PHP7.0.0 有大约 27 个错误 被压扁了PHP7.0.1;在其他固定项目中。
来源:PHP.net changelog。
我还查看了您上面的 PHP 代码 (戴着我的 google 眼镜),但它非常简单。我怀疑它有什么问题。虽然我猜它与 PHP7 处理 flush()[=53= 的方式有关] 和输出。
此外:
注意到您的更新(特别是 更新 1 和 更新 2);我真的必须在那里表扬你! 令人印象深刻。
请务必查看此已修复的错误 #61751。如果我对你的 PHP 版本的看法是正确的,那么这个修复的错误可能已经解决了你的问题;你只需要迁移到 PHP7.0.1.
注意: 我知道我应该检查已修复错误的内部结构,但是...
它 is/was PHP7 中的一个错误,最近用 https://github.com/php/php-src/pull/1745 修复了。它尚未在任何正式版本中发布,但最终会在某个时候发布。
在上述 PR 之前,还报告了一个描述类似问题的错误:https://bugs.php.net/bug.php?id=71466
我正在从客户端发送 POST 请求(使用 curl
和自定义 nodejs 脚本进行测试),但没有正确返回响应。 PHP 5.6.
环境
整个事情尽量减少:
- Vagrant VM 中的所有内容 运行 Ubuntu 14.04 LTS
- nginx 1.9.7 来自 http://nginx.org/packages/ubuntu/
- PHP7 FPM 编译自官方来源
--disable-all --enable-fpm
我正在使用的最小 nginx 站点配置:
server {
listen 80;
server_name localhost;
location / {
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_pass unix:/var/run/php/php7.0-fpm-api.sock;
fastcgi_param SCRIPT_FILENAME /vagrant/index.php;
}
}
示例 PHP 来自 /vagrant/index.php
的脚本:
<?php
echo str_repeat('.', 512);
flush(); // not necessary, only due testing
我正在使用的 curl 调用:curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
我正在使用的 NodeJS 脚本:
'use strict';
var http = require('http');
var url = require('url');
var uri = url.parse(process.env.URL);
var options = {
method: 'POST', protocol: uri.protocol, hostname: uri.hostname,
port: uri.port, path: uri.path,
};
var data = '';
var httpRequest = http.request(options, function(res) {
res.on('data', function(chunk) {
console.log('received data', chunk.length);
data += chunk;
});
res.on('end', function() { console.log('final size', data.length); });
})
.on('error', function(err) { console.log(err); });
httpRequest.write('');
httpRequest.end();
正在将我的测试请求发送到 PHP 5.6
$ curl http://localhost/
..........[cut off]
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
..........[cut off]
$ URL=http://localhost/ node php7test.js
received data 512
final size 512
正在将我的测试请求发送到 PHP 7.0
$ curl http://localhost/
..........[cut off]
$ URL=http://localhost/ node php7test.js
final size 0
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
curl: (18) transfer closed with outstanding read data remaining
为什么我要乱用分块编码?
没有商业理由这样做,但是我使用了一个非常相似的 NodeJS 代码,默认为分块编码,切换到 PHP7 时突然停止工作。
我发现以下内容可以从 nodejs 端工作:显式设置 Content-Length
header 删除由 NodeJS 发送的隐式 Transfer-Encoding: chunked
header 并因此工作两个 PHP 版本。
但是我想了解为什么 PHP7 在这里表现不同,以及我是否有误或者这里到底发生了什么。
更新一:
- 我比较了 5.6 和 7.0 之间的
sapi/fpm/
来源,除了由于 PHP 内部变化 引起的变化外,我几乎看不出任何区别
- built-in服务器(
php -S
)不受影响,所有测试
更新二:
我将 PHP 来源一分为二,并且能够查明行为发生变化的时间:
- 我能够编译的最后一次提交: https://github.com/php/php-src/commit/16265a59ac6bd433bfb636e4e44da1ad57cdcda9
- 第一次提交我能够再次编译但没有用:https://github.com/php/php-src/commit/86de98cabada88f4667839794c176ea37648498b
在两者之间,git bisect
的输出,我无法编译的提交:
$ git bisect skip
There are only 'skip'ped commits left to test.
The first bad commit could be any of:
ba5ecf355fe792a5a2a8e6582d5e081d02b16fbf
e383cb4493031a7cd952cfcaed3297e583149c07
fef18f4bea1980a59a9283c2197bd090aaf500cb
18cf4e0a8a574034f60f4d123407c173e57e54ec
We cannot bisect more!
感觉这可能是一个错误,我将其写给内部人员,也许他们有一些见解:https://marc.info/?l=php-internals&m=145090900217798&w=2
从你的 post 我猜你正在使用 PHP7.0.0。如果我的猜测是 (bool) TRUE 那么我建议你迁移到 PHP7.0.1.
PHP7.0.0 有大约 27 个错误 被压扁了PHP7.0.1;在其他固定项目中。
来源:PHP.net changelog。
我还查看了您上面的 PHP 代码 (戴着我的 google 眼镜),但它非常简单。我怀疑它有什么问题。虽然我猜它与 PHP7 处理 flush()[=53= 的方式有关] 和输出。
此外:
注意到您的更新(特别是 更新 1 和 更新 2);我真的必须在那里表扬你! 令人印象深刻。 请务必查看此已修复的错误 #61751。如果我对你的 PHP 版本的看法是正确的,那么这个修复的错误可能已经解决了你的问题;你只需要迁移到 PHP7.0.1.
注意: 我知道我应该检查已修复错误的内部结构,但是...
它 is/was PHP7 中的一个错误,最近用 https://github.com/php/php-src/pull/1745 修复了。它尚未在任何正式版本中发布,但最终会在某个时候发布。
在上述 PR 之前,还报告了一个描述类似问题的错误:https://bugs.php.net/bug.php?id=71466