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

如何在Laravel中全局修改Saloon/Guzzle以捕获500错误上报Sentry?

全局捕获Saloon请求500状态码并上报Sentry的方案

针对你的需求,无需逐个修改20余个服务的请求代码,以下两种优雅的全局实现方式可以解决问题:

方案一:使用Saloon全局请求中间件(推荐)

Saloon原生支持请求/响应中间件,通过全局注册中间件,可拦截所有Saloon请求的响应,自动检查状态码并上报。

步骤1:创建自定义中间件

在项目中新建中间件文件 app/Saloon/Middlewares/ReportServerErrorMiddleware.php:

<?php

namespace App\Saloon\Middlewares;

use Saloon\Contracts\Middleware;
use Saloon\Contracts\Request;
use Saloon\Contracts\Response;
use Exception;

class ReportServerErrorMiddleware implements Middleware
{
    // 请求发送前无需处理,留空即可
    public function handleRequest(Request $request): void {}

    public function handleResponse(Response $response): void
    {
        // 检查响应状态码是否为500及以上
        if ($response->status() >= 500) {
            // 构造异常,包含请求信息便于排查
            $exception = new Exception(
                sprintf(
                    '外部API服务器错误: %s %s 返回状态码 %d',
                    $response->getRequest()->getMethod(),
                    $response->getRequest()->getUrl(),
                    $response->status()
                ),
                $response->status()
            );

            // 给Sentry附加请求/响应详情,方便定位问题
            app('sentry')->configureScope(function (\Sentry\State\Scope $scope) use ($response) {
                $scope->setContext('external_api_request', [
                    'method' => $response->getRequest()->getMethod(),
                    'url' => $response->getRequest()->getUrl(),
                    'headers' => $response->getRequest()->headers()->all(),
                    'body' => $response->getRequest()->body()->all(),
                ]);

                $scope->setContext('external_api_response', [
                    'status' => $response->status(),
                    'headers' => $response->headers()->all(),
                    'body' => $response->body(),
                ]);
            });

            // 触发Laravel的异常上报,自动走你已配置的Sentry逻辑
            report($exception);
        }
    }
}

步骤2:全局注册中间件

在 app/Providers/AppServiceProvider.php 的 boot 方法中注册该中间件:

use Saloon\Facades\Saloon;
use App\Saloon\Middlewares\ReportServerErrorMiddleware;

public function boot()
{
    // 注册Saloon全局中间件
    Saloon::globalMiddleware([
        ReportServerErrorMiddleware::class,
    ]);
}

方案二:使用Guzzle底层中间件

如果希望从Guzzle层面拦截所有HTTP请求(包括非Saloon发起的Guzzle请求),可以通过Guzzle的HandlerStack添加中间件。

步骤1:创建Guzzle中间件

新建文件 app/Guzzle/Middlewares/ReportServerErrorMiddleware.php:

<?php

namespace App\Guzzle\Middlewares;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Exception;

class ReportServerErrorMiddleware
{
    public function __invoke(callable $handler)
    {
        return function (RequestInterface $request, array $options) use ($handler) {
            return $handler($request, $options)->then(function (ResponseInterface $response) use ($request) {
                if ($response->getStatusCode() >= 500) {
                    $exception = new Exception(
                        sprintf(
                            '外部API服务器错误: %s %s 返回状态码 %d',
                            $request->getMethod(),
                            $request->getUri()->__toString(),
                            $response->getStatusCode()
                        ),
                        $response->getStatusCode()
                    );

                    // 附加请求/响应上下文到Sentry
                    app('sentry')->configureScope(function (\Sentry\State\Scope $scope) use ($request, $response) {
                        $scope->setContext('external_api_request', [
                            'method' => $request->getMethod(),
                            'url' => $request->getUri()->__toString(),
                            'headers' => $request->getHeaders(),
                            'body' => (string)$request->getBody(),
                        ]);

                        $scope->setContext('external_api_response', [
                            'status' => $response->getStatusCode(),
                            'headers' => $response->getHeaders(),
                            'body' => (string)$response->getBody(),
                        ]);
                    });

                    report($exception);
                }

                return $response;
            });
        };
    }
}

步骤2:全局配置Saloon使用该中间件

同样在 AppServiceProvider 的 boot 方法中添加:

use Saloon\Facades\Saloon;
use App\Guzzle\Middlewares\ReportServerErrorMiddleware;

public function boot()
{
    // 给所有Saloon请求添加Guzzle中间件
    Saloon::globalRequestMiddleware(function ($request) {
        $request->withMiddleware([
            new ReportServerErrorMiddleware(),
        ]);
    });
}

方案对比

  • Saloon中间件:更贴合Saloon生态,直接操作Saloon的Request/Response对象,无需转换格式,仅对Saloon请求生效,推荐使用。
  • Guzzle中间件:从底层拦截所有Guzzle请求,适合项目中存在其他非Saloon的Guzzle请求场景,覆盖范围更广。

配置完成后,所有Saloon请求返回500+状态码时都会自动触发Sentry告警,后续新增的服务也会自动生效,无需逐个修改请求代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:13:29