在Spring RestClient出错时,有没有办法记录完整的请求和响应?

后端开发 2026-07-09

我已经在这项任务上卡了相当长的时间。看起来很简单:每当RestClient请求发生错误时,我希望记录请求和响应的数据,以及它们的主体,供调试之用。

然而,RestClient似乎只能记录请求数据。对于非HTTP错误的情况,例如JSON反序列化不匹配,响应体似乎不会出现在日志中,尽管响应体已成功接收,只是格式出乎意料。

现在,我有很多通过RestClient发出的请求,收到的响应是一个字符串,然后手动将其解析为JSON,再自行处理错误。这个做法越来越让人头疼。

是否有办法在同一个位置同时捕获HTTP错误和JSON解析/反序列化错误,并在使用RestClient时记录完整的请求和响应?

同样的问题似乎也同样适用于WebClient,因为据我所知,它也缺乏对正文解析/反序列化错误的恰当处理程序。

注意:我并不想记录所有请求和响应——只有发生错误时的那些。

解决方案

在Copilot的帮助下。你需要对响应进行缓冲,这样就可以读取两遍。

public class ErrorOnlyLoggingInterceptor implements ClientHttpRequestInterceptor {

    private static final Logger log = LoggerFactory.getLogger(ErrorOnlyLoggingInterceptor.class);

    @Override
    public ClientHttpResponse intercept(
            HttpRequest request,
            byte[] body,
            ClientHttpRequestExecution execution) throws IOException {

        ClientHttpResponse response = null;

        try {
            response = execution.execute(request, body);

            // Wrap so we can read body safely
            ClientHttpResponse wrapped =
                    new BufferingClientHttpResponseWrapper(response);

            // Only log on error status
            if (wrapped.getStatusCode().isError()) {

                String requestBody = new String(body, StandardCharsets.UTF_8);
                String responseBody = new String(
                        wrapped.getBody().readAllBytes(),
                        StandardCharsets.UTF_8
                );

                log.error("""
                        HTTP call failed
                        URI: {}
                        Method: {}
                        Status: {}
                        Request Body: {}
                        Response Body: {}
                        """,
                        request.getURI(),
                        request.getMethod(),
                        wrapped.getStatusCode(),
                        requestBody,
                        responseBody
                );
            }

            return wrapped;

        } catch (Exception ex) {
            // Also log transport errors (timeouts, DNS, etc.)
            log.error("""
                    HTTP call threw exception
                    URI: {}
                    Method: {}
                    Request Body: {}
                    Exception: {}
                    """,
                    request.getURI(),
                    request.getMethod(),
                    new String(body, StandardCharsets.UTF_8),
                    ex.getMessage(),
                    ex
            );

            throw ex;
        }
    }
}

然后把它集成到你的RestClient中(假设Spring 4)

RestClient client = RestClient.builder()
        .requestFactory(
                new BufferingClientHttpRequestFactory(
                        new SimpleClientHttpRequestFactory()
                )
        )
        .requestInterceptor(new LoggingInterceptor())
        .build();
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章