You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel HTTP客户端如何对200含特定错误的响应执行重试?

Laravel HTTP客户端:对含特定错误的200响应执行重试

问题描述

对接的API存在两种需要重试的场景:

  • 返回非客户端错误(如5xx状态码)
  • 返回200状态码,但响应JSON中包含errors字段且存在特定错误消息(如error but retry)

使用Laravel HTTP客户端的retry()闭包实现时,发现仅当请求抛出异常时闭包才会执行,导致含错误的200响应无法触发重试。当前代码能对502错误重试、遇到401停止,但不会处理含错误的200响应。

用户尝试的代码

$response = Http::acceptJson()
->retry([100,200], when: function($exception, $request) {
  if ($exception instanceof \Illuminate\Http\Client\RequestException) {
      return !$exception->response->clientError();
  }

  if ($exception instanceOf \Illuminate\Http\Client\Response) {
    $response = $exception;
    if ($response->ok() && fluent($response->json())->collect('errors')->pluck('message')->contains('error but retry')) {
      return true;
    }
  }

  return false;
})
->get('http://localhost:3001/test')

模拟API返回顺序

  • 502 Bad Gateway
  • 200状态码,响应内容:{"errors": [{"message": "error but retry"}]}
  • 200状态码,响应内容:{"data": [{"one": 1}]}
  • 401 Unauthorized

解决方案

Laravel HTTP客户端的retry()默认仅在请求抛出异常时触发判断逻辑。要实现对200错误响应的重试,需主动将符合条件的200响应转换为异常,让retry机制捕获。

最终实现代码

$response = Http::acceptJson()
    ->retry(
        times: 3,
        sleep: [100, 200],
        when: function ($exception, $request) {
            // 处理非客户端错误的异常(如5xx)
            if ($exception instanceof \Illuminate\Http\Client\RequestException) {
                return !$exception->response->clientError();
            }

            // 处理主动抛出的、携带响应的自定义异常
            if ($exception instanceof \RuntimeException && property_exists($exception, 'response')) {
                return true;
            }

            return false;
        }
    )
    ->get('http://localhost:3001/test')
    // 检查200响应是否包含需要重试的错误,是则抛出异常触发重试
    ->throwIf(function ($response) {
        if ($response->ok()) {
            $errorMessages = collect($response->json('errors', []))->pluck('message');
            return $errorMessages->contains('error but retry');
        }
        // 非200响应交给默认异常处理(如401不会触发重试)
        return false;
    }, function ($response) {
        $exception = new \RuntimeException('Retryable error in 200 response');
        $exception->response = $response;
        return $exception;
    });

关键逻辑说明

  1. throwIf()的作用:在请求成功返回后,检查200响应是否包含目标错误消息。如果符合条件,抛出携带响应对象的自定义RuntimeException,触发retry机制。
  2. retry()闭包扩展:新增对自定义异常的判断,只要是我们主动抛出的异常,就返回true执行重试。
  3. 重试次数控制:设置times:3可覆盖模拟场景中的前三次请求(502→错误200→正常200),最终获取有效响应。
  4. 客户端错误处理:401这类4xx客户端错误会被RequestException捕获,!$exception->response->clientError()返回false,因此不会触发重试,符合预期。

内容的提问来源于stack exchange,提问作者wivku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:17:05