首页
下载
文档
社区
视频
捐赠
源代码
赞助商
AOT 编译器
AI 助理
商业产品
PHP AOT 原生编译器
Swoole-Compiler 代码加密器
CRMEB 新零售社交电商系统
登录
注册
全部
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
发表新帖
使用 Guzzle 上传大数据时报错, 方法从 POST 变成了 PUT
### 问题描述 下述代码在本地测试没有问题, 使用 Ubuntu 的 docker 镜像时, 报错. 请求的 `POST` 方法变成 `PUT` ### 测试docker镜像 ```sh docker run -it --name guzzle-swoole liuende501/swoole-guzzle-test "/bin/bash" # 启动后 cd /var/opt/ php guzzle/httpbin.php # 调试 USE_ZEND_ALLOC=0 valgrind -s php guzzle/httpbin.php ``` ### Swoole版本,PHP版本,以及操作系统版本信息 PHP 7.4.25 **操作系统** ``` Distributor ID: Ubuntu Description: Ubuntu 20.04.3 LTS Release: 20.04 Codename: focal ``` **swoole** ``` swoole Swoole => enabled Author => Swoole Team <team@swoole.com> Version => 4.8.0 Built => Oct 25 2021 15:31:15 coroutine => enabled with boost asm context debug => enabled trace_log => enabled epoll => enabled eventfd => enabled signalfd => enabled cpu_affinity => enabled spinlock => enabled rwlock => enabled sockets => enabled openssl => OpenSSL 1.1.1f 31 Mar 2020 dtls => enabled http2 => enabled pcre => enabled mutex_timedlock => enabled pthread_barrier => enabled futex => enabled mysqlnd => enabled async_redis => enabled Directive => Local Value => Master Value swoole.enable_coroutine => On => On swoole.enable_library => On => On swoole.enable_preemptive_scheduler => Off => Off swoole.display_errors => On => On swoole.use_shortname => Off => Off swoole.unixsock_buffer_size => 8388608 => 8388608 ``` ### 相关代码 ```php <?php require_once 'vendor/autoload.php'; use GuzzleHttp\Client; use Swoole\Runtime; use function Swoole\Coroutine\run; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); run(function () { // 1.jpg 大于2M $imgBase64 = base64_encode(file_get_contents('guzzle/1.jpg')); $data['json']['Image'] = $imgBase64; $client = new Client([ "base_uri" => "http://httpbin.org/anything", "connect_timeout" => 5, "timeout" => 60, "verify" => false, "debug" => true ]); echo "starting" . PHP_EOL; try { $res = $client->request('POST', '', $data); echo "request end" . PHP_EOL; echo $res->getBody()->getContents(); }catch (\Throwable $e){ echo $e->getMessage(); } echo PHP_EOL . "end" . PHP_EOL; }); ``` ### 你期待的结果是什么?实际看到的错误信息又是什么? 从 httpbin.org 响应我的请求数据, 实际看到的是 ``` The cURL request was retried 3 times and did not succeed. The most likely reason for the failure is that cURL was unable to rewind the body of the request and subsequent retries resulted in the same error. Turn on the debug option to see what went wrong. ```
发布于4年前 · 26 次浏览 · 来自
提问
shichen
### 问题描述 下述代码在本地测试没有问题, 使用 Ubuntu 的 docker 镜像时, 报错. 请求的 `POST` 方法变成 `PUT` ### 测试docker镜像 ```sh docker run -it --name guzzle-swoole liuende501/swoole-guzzle-test "/bin/bash" # 启动后 cd /var/opt/ php guzzle/httpbin.php # 调试 USE_ZEND_ALLOC=0 valgrind -s php guzzle/httpbin.php ``` ### Swoole版本,PHP版本,以及操作系统版本信息 PHP 7.4.25 **操作系统** ``` Distributor ID: Ubuntu Description: Ubuntu 20.04.3 LTS Release: 20.04 Codename: focal ``` **swoole** ``` swoole Swoole => enabled Author => Swoole Team <team@swoole.com> Version => 4.8.0 Built => Oct 25 2021 15:31:15 coroutine => enabled with boost asm context debug => enabled trace_log => enabled epoll => enabled eventfd => enabled signalfd => enabled cpu_affinity => enabled spinlock => enabled rwlock => enabled sockets => enabled openssl => OpenSSL 1.1.1f 31 Mar 2020 dtls => enabled http2 => enabled pcre => enabled mutex_timedlock => enabled pthread_barrier => enabled futex => enabled mysqlnd => enabled async_redis => enabled Directive => Local Value => Master Value swoole.enable_coroutine => On => On swoole.enable_library => On => On swoole.enable_preemptive_scheduler => Off => Off swoole.display_errors => On => On swoole.use_shortname => Off => Off swoole.unixsock_buffer_size => 8388608 => 8388608 ``` ### 相关代码 ```php <?php require_once 'vendor/autoload.php'; use GuzzleHttp\Client; use Swoole\Runtime; use function Swoole\Coroutine\run; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); run(function () { // 1.jpg 大于2M $imgBase64 = base64_encode(file_get_contents('guzzle/1.jpg')); $data['json']['Image'] = $imgBase64; $client = new Client([ "base_uri" => "http://httpbin.org/anything", "connect_timeout" => 5, "timeout" => 60, "verify" => false, "debug" => true ]); echo "starting" . PHP_EOL; try { $res = $client->request('POST', '', $data); echo "request end" . PHP_EOL; echo $res->getBody()->getContents(); }catch (\Throwable $e){ echo $e->getMessage(); } echo PHP_EOL . "end" . PHP_EOL; }); ``` ### 你期待的结果是什么?实际看到的错误信息又是什么? 从 httpbin.org 响应我的请求数据, 实际看到的是 ``` The cURL request was retried 3 times and did not succeed. The most likely reason for the failure is that cURL was unable to rewind the body of the request and subsequent retries resulted in the same error. Turn on the debug option to see what went wrong. ```
赞
0
收藏
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
登录
后参与评论
评论
2021-10-26
鲁飞
你本地是什么环境? `SWOOLE_HOOK_ALL` 包含 `HOOK_CURL`,可以关闭掉看下 ```php SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_CURL ```
赞
0
回复
2021-10-26
shichen
关闭请求成功, 我是用 hyperf 进行开发的, web服务器如果不能一键协程化是不是有问题
赞
0
回复
2021-10-26
鲁飞
回复
shichen
你可以用`SWOOLE_HOOK_NATIVE_CURL` https://wiki.swoole.com/#/runtime?id=swoole_hook_native_curl
赞
0
回复
2021-10-26
shichen
回复
鲁飞
`SWOOLE_HOOK_NATIVE_CURL` 这个我也测试过, 是成功的 我想知道 `SWOOLE_HOOK_CURL` 这个为什么为有问题, `POST` 会变成 `PUT`
赞
0
回复
2021-10-26
shichen
回复
鲁飞
`SWOOLE_HOOK_NATIVE_CURL` 和 `SWOOLE_HOOK_CURL` 有什么区别
赞
0
回复
2021-10-26
鲁飞
回复
shichen
这个问题就要看源码了。 ```php #guzzle vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php private function applyBody(RequestInterface $request, array $options, array &$conf): void { $size = $request->hasHeader('Content-Length') ? (int) $request->getHeaderLine('Content-Length') : null; // Send the body as a string if the size is less than 1MB OR if the // [curl][body_as_string] request value is set. if (($size !== null && $size < 1000000) || !empty($options['_body_as_string'])) { $conf[\CURLOPT_POSTFIELDS] = (string) $request->getBody(); // Don't duplicate the Content-Length header $this->removeHeader('Content-Length', $conf); $this->removeHeader('Transfer-Encoding', $conf); } else { $conf[\CURLOPT_UPLOAD] = true; if ($size !== null) { $conf[\CURLOPT_INFILESIZE] = $size; $this->removeHeader('Content-Length', $conf); } $body = $request->getBody(); if ($body->isSeekable()) { $body->rewind(); } $conf[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) { return $body->read($length); }; } // If the Expect header is not present, prevent curl from adding it if (!$request->hasHeader('Expect')) { $conf[\CURLOPT_HTTPHEADER][] = 'Expect:'; } // cURL sometimes adds a content-type by default. Prevent this. if (!$request->hasHeader('Content-Type')) { $conf[\CURLOPT_HTTPHEADER][] = 'Content-Type:'; } } ``` 你的文件大于了1MB,所以设置了`CURLOPT_UPLOAD`; HOOK_CURL 是由 library 实现的,再来看下 https://github.com/swoole/library/blob/038e7d29d847f3e02b335c955cedc6cd4bbef949/src/core/Curl/Handler.php#L670-L672 设置了 method 为 `PUT`
赞
1
回复
2021-10-26
shichen
回复
鲁飞
你好 按照这个逻辑来 `SWOOLE_HOOK_CURL ` 不能用于文件大于1M的上传, 是吗
赞
0
回复
2021-10-26
鲁飞
回复
shichen
你用`SWOOLE_HOOK_NATIVE_CURL `就行
赞
0
回复
2021-11-01
李铭昕
用 SWOOLE_HOOK_NATIVE_CURL 吧,这个稳多了。。。
赞
0
回复