Laravel HTTP Client Pool捕获ConnectException及并发请求故障处理方案
问题根因
你当前的写法无效是因为两个核心错误:
- 异步请求的异常不会在创建Promise的同步阶段抛出,你套在
$pool->get()外面的try/catch完全不会触发 - Laravel HTTP客户端的pool是批量并发执行所有你返回的Promise,你在循环里写的重试逻辑只是在创建阶段重复生成请求,没有真正实现请求失败后的重试逻辑
解决方案
我们可以直接利用Laravel HTTP客户端内置的retry方法,配合异常判断逻辑,实现连接异常时自动更换代理重试,不需要自己写循环捕获:
<?php use GuzzleHttp\Exception\ConnectException; use Illuminate\Support\Facades\Http; $responses = Http::pool(function (Illuminate\Http\Client\Pool $pool) use ($params) { $url = "https://example.com/api/endpoint?foo=%s"; $requests = []; foreach ($params as $param) { $requests[] = $pool->as($param) // 配置重试规则:最多重试10次,每次间隔100ms,仅连接异常时重试 ->retry(10, 100, function (\Exception $e, $request) { // 仅当是连接异常时才触发重试 if ($e instanceof ConnectException) { // 每次重试更换新的代理 $request->withOptions(['proxy' => $this->proxyManager->get()]); return true; } return false; }) // 初始赋值第一个代理 ->withOptions(['proxy' => $this->proxyManager->get()]) ->get(sprintf($url, $param)); } return $requests; }); // 后续可以遍历responses判断每个请求的最终状态 foreach ($responses as $param => $response) { if ($response->failed()) { // 处理重试10次后仍然失败的情况 info("参数{$param}请求最终失败", ['error' => $response->toException()?->getMessage()]); } }
注意事项
- 如果你需要更灵活的重试间隔,可以把
retry方法的第二个参数换成回调,实现指数退避之类的逻辑 - 所有请求还是保持并发执行,每个请求的重试是独立的,不会互相阻塞
- 如果要获取每个请求的异常信息,可以调用
$response->toException()方法获取抛出的异常实例 - 不要在pool的闭包内用
dd之类的终止函数,会打断整个并发池的执行
内容的提问来源于stack exchange,提问作者abr
相关产品推荐
相关产品推荐

