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

Spring Boot中如何将Rest Client日志存入变量并落地至数据库?

How to Capture Spring Boot Rest Client Requests/Responses and Store in Database

Great question! Spring Boot doesn’t offer out-of-the-box configuration to directly capture those Apache HTTP wire logs into variables and persist them to a database. The core issue here is that those debug logs are meant for console/file output, not structured data capture. Instead, the more reliable approach is to intercept the Rest Client's requests and responses directly (rather than parsing log strings), which gives you clean, structured data to store.

Let’s break this down based on the two most common Spring Boot Rest Clients:

1. For RestTemplate

You can create a custom ClientHttpRequestInterceptor to hook into the request/response lifecycle:

Step 1: Create the Interceptor

@Component
public class RestClientLoggingInterceptor implements ClientHttpRequestInterceptor {

    private final RestClientLogRepository logRepository; // Your JPA/CRUD repository

    public RestClientLoggingInterceptor(RestClientLogRepository logRepository) {
        this.logRepository = logRepository;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // Capture request details
        String requestUri = request.getURI().toString();
        String requestMethod = request.getMethod().name();
        String requestBody = new String(body, StandardCharsets.UTF_8);

        // Execute the request and get response
        ClientHttpResponse response = execution.execute(request, body);

        // Capture response details
        int statusCode = response.getStatusCode().value();
        String responseBody = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);

        // Create log entity and save to DB
        RestClientLog logEntry = new RestClientLog();
        logEntry.setRequestUri(requestUri);
        logEntry.setRequestMethod(requestMethod);
        logEntry.setRequestBody(requestBody);
        logEntry.setResponseStatusCode(statusCode);
        logEntry.setResponseBody(responseBody);
        logEntry.setTimestamp(LocalDateTime.now());

        logRepository.save(logEntry);

        return response;
    }
}

Step 2: Register the Interceptor with RestTemplate

@Configuration
public class RestTemplateConfig {

    @Autowired
    private RestClientLoggingInterceptor loggingInterceptor;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(loggingInterceptor);
        return restTemplate;
    }
}

2. For WebClient

WebClient uses ExchangeFilterFunction to intercept requests/responses:

Step 1: Create the Filter Function

@Component
public class WebClientLoggingFilter {

    private final RestClientLogRepository logRepository;

    public WebClientLoggingFilter(RestClientLogRepository logRepository) {
        this.logRepository = logRepository;
    }

    public ExchangeFilterFunction logRequestResponse() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            // Capture request details
            String requestUri = clientRequest.url().toString();
            String requestMethod = clientRequest.method().name();
            
            // Read request body (WebClient buffers the body to read it safely)
            return clientRequest.body()
                    .map(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        DataBufferUtils.release(dataBuffer);
                        String requestBody = new String(bytes, StandardCharsets.UTF_8);

                        // Store request temp data to pair with response later
                        Map<String, Object> requestData = new HashMap<>();
                        requestData.put("uri", requestUri);
                        requestData.put("method", requestMethod);
                        requestData.put("body", requestBody);
                        requestData.put("timestamp", LocalDateTime.now());

                        return ClientRequest.from(clientRequest)
                                .body(BodyInserters.fromValue(bytes))
                                .attribute("requestData", requestData)
                                .build();
                    });
        }).andThen(ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            // Retrieve request data from request attributes
            Map<String, Object> requestData = clientResponse.request().attributes().get("requestData");

            // Capture response details
            int statusCode = clientResponse.statusCode().value();
            return clientResponse.bodyToMono(String.class)
                    .map(responseBody -> {
                        // Create log entity and save to DB
                        RestClientLog logEntry = new RestClientLog();
                        logEntry.setRequestUri((String) requestData.get("uri"));
                        logEntry.setRequestMethod((String) requestData.get("method"));
                        logEntry.setRequestBody((String) requestData.get("body"));
                        logEntry.setResponseStatusCode(statusCode);
                        logEntry.setResponseBody(responseBody);
                        logEntry.setTimestamp((LocalDateTime) requestData.get("timestamp"));

                        logRepository.save(logEntry);

                        return clientResponse;
                    });
        }));
    }
}

Step 2: Register the Filter with WebClient

@Configuration
public class WebClientConfig {

    @Autowired
    private WebClientLoggingFilter loggingFilter;

    @Bean
    public WebClient webClient() {
        return WebClient.builder()
                .filter(loggingFilter.logRequestResponse())
                .build();
    }
}

What About Parsing the Apache HTTP Wire Logs?

While it’s technically possible to create a custom log appender (e.g., for Logback or Log4j2) to parse the wire logs and persist them, this approach is not recommended. The wire logs are unstructured strings, so parsing them to extract request/response bodies, URIs, etc., is fragile—any change to the log format (e.g., Apache HTTP client updates) could break your parsing logic. Direct interception is far more reliable and maintainable.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:52:03