GuzzleHTTP requestAsync自定义超时不生效(Laravel项目)
针对你遇到的Guzzle设置60秒超时但实际30秒就触发超时(cURL错误28)的问题,结合你的代码和排查情况,给出几个容易忽略的排查方向:
1. 检查Web环境下的PHP max_execution_time
你可能只检查了CLI版本的php.ini,但Laravel在Web环境运行时,使用的是Web服务器对应的php.ini(比如Nginx对应的php-fpm php.ini)。很多环境默认将max_execution_time设为30秒,这个参数会强制终止超时的PHP脚本,导致Guzzle请求还没到自己的60秒超时就被中断。
验证方式:在代码中添加echo ini_get('max_execution_time');,查看实际生效的值。如果是30,修改对应php.ini中的该参数为90+,然后重启Web服务/PHP-FPM。
2. 检查Laravel队列超时(如果请求在队列中执行)
如果这段Guzzle请求是在Laravel队列任务里运行的,默认队列任务的timeout配置是30秒(在config/queue.php中)。队列系统会在任务运行超过这个时间后强制终止进程,导致Guzzle请求中断。
解决:修改config/queue.php中对应队列连接的timeout参数为90,或者在任务类中设置public $timeout = 90;。
3. 检查Nginx的fastcgi_read_timeout
如果你的Laravel应用通过Nginx+PHP-FPM部署,Nginx的fastcgi_read_timeout参数会限制Nginx等待PHP-FPM响应的时间,部分环境默认设为30秒。超过这个时间Nginx会直接返回504错误,同时终止PHP进程。
解决:在Nginx的站点配置中添加或修改:
fastcgi_read_timeout 90s;
然后重启Nginx。
4. 检查PHP的default_socket_timeout
Guzzle如果使用Stream Handler而非cURL Handler时,会受PHP的default_socket_timeout参数影响。即使你设置了Guzzle的timeout,如果这个系统级参数被设为30秒,会覆盖Guzzle的设置。
验证:在代码中输出echo ini_get('default_socket_timeout');,如果是30,修改php.ini中的该参数为90+,重启服务。
5. 确认Guzzle使用的Handler类型
你的代码中用了HandlerStack::create(),默认会优先使用cURL Handler(如果环境支持cURL),但如果环境中cURL不可用,会 fallback到Stream Handler。不同Handler的超时逻辑略有差异,你可以在代码中打印Handler类型确认:
$handler = HandlerStack::create(); var_dump(get_class($handler->getHandler()));
如果是GuzzleHttp\Handler\StreamHandler,则需要重点检查default_socket_timeout;如果是CurlHandler,则确认cURL的版本是否支持长超时,同时检查是否有其他中间件覆盖了CURLOPT_TIMEOUT配置。
6. 排查目标服务器的超时限制
虽然你的错误提示是客户端超时,但也有可能是目标服务器设置了30秒的连接/响应超时,主动断开了连接。可以用curl命令直接测试目标接口:
curl -X [请求方法] [目标URL] -H "Authorization: token" --max-time 60 -v
看是否同样在30秒左右断开,如果是,需要联系目标服务方调整超时设置。
内容的提问来源于stack exchange,提问作者nrkdrk

