1. 개요

이 예제에서는 반응형 HTTP 클라이언트인 Spring의 WebClient 를 사용자 지정 하여 요청과 응답을 기록하는 방법을 보여줍니다.

2. 웹클라이언트

WebClient 는 Spring WebFlux 를 기반으로 하는 HTTP 요청에 대한 반응형 비차단 인터페이스입니다 . 선언적 구성을 위한 반응형 유형이 있는 기능적이고 유창한 API가 있습니다.

배후에서 WebClient 는 HTTP 클라이언트를 호출합니다. Reactor Netty가 기본이며 Jetty의 반응형 HttpClient 도 지원됩니다. 또한 WebClient 용 ClientConnector설정하여 HTTP 클라이언트의 다른 구현을 연결할 수 있습니다 .

3. 요청 및 응답 로깅

WebClient 에서 사용하는 기본 HttpClient 는 Netty 구현이므로 react.netty.http.client 로깅 수준을 DEBUG 로 변경한 후 일부 요청 로깅을 볼 수 있지만 사용자 지정 로그가 필요한 경우 다음을 통해 로거를 구성 할 수 있습니다. WebClient#filters :

WebClient
  .builder()
  .filters(exchangeFilterFunctions -> {
      exchangeFilterFunctions.add(logRequest());
      exchangeFilterFunctions.add(logResponse());
  })
  .build()

이 코드 스니펫에서는 요청과 응답을 기록하기 위해 두 개의 별도 필터를 추가했습니다.

ExchangeFilterFunction#ofRequestProcessor 를 사용하여 logRequest 를 구현해 보겠습니다 .

ExchangeFilterFunction logRequest() {
    return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
        if (log.isDebugEnabled()) {
            StringBuilder sb = new StringBuilder("Request: \n");
            //append clientRequest method and url
            clientRequest
              .headers()
              .forEach((name, values) -> values.forEach(value -> /* append header key/value */));
            log.debug(sb.toString());
        }
        return Mono.just(clientRequest);
    });
}

logResponse 는 동일 하지만 대신 ExchangeFilterFunction#ofResponseProcessor 를 사용해야 합니다.

이제 react.netty.http.client 로그 수준을 INFO 또는 ERROR 로 변경하여 보다 깔끔한 출력을 얻을 수 있습니다.

4. Body를 통한 로깅 요청 및 응답

HTTP 클라이언트에는 요청 및 Response body을 기록하는 기능이 있습니다. 따라서 목표를 달성하기 위해 WebClient 와 함께 로그 지원 HTTP 클라이언트를 사용할 것 입니다.

WebClient.Builder# clientConnector  를 수동으로 설정하여 이를 수행할 수 있습니다. Jetty 및 Netty HTTP 클라이언트를 살펴보겠습니다.

4.1. Jetty HttpClient 로 로깅

먼저, pom 에 jetty-reactive-httpclient 에 대한 Maven 의존성을 추가해 보겠습니다 .

<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-reactive-httpclient</artifactId>
    <version>1.1.6</version>
</dependency>

그런 다음 Custom형 Jetty HttpClient 를 생성할 것입니다 .

SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
HttpClient httpClient = new HttpClient(sslContextFactory) {
    @Override
    public Request newRequest(URI uri) {
        Request request = super.newRequest(uri);
        return enhance(request);
    }
};

여기서는 HttpClient#newRequest 를 재정의한 다음 요청 을 로그 인핸서 로 래핑했습니다 .

다음으로 요청의 각 부분을 사용할 수 있을 때 기록할 수 있도록 요청에 이벤트를 등록해야 합니다.

Request enhance(Request request) {
    StringBuilder group = new StringBuilder();
    request.onRequestBegin(theRequest -> {
        // append request url and method to group
    });
    request.onRequestHeaders(theRequest -> {
        for (HttpField header : theRequest.getHeaders()) {
            // append request headers to group
        }
    });
    request.onRequestContent((theRequest, content) -> {
        // append content to group
    });
    request.onRequestSuccess(theRequest -> {
        log.debug(group.toString());
        group.delete(0, group.length());
    });
    group.append("\n");
    request.onResponseBegin(theResponse -> {
        // append response status to group
    });
    request.onResponseHeaders(theResponse -> {
        for (HttpField header : theResponse.getHeaders()) {
            // append response headers to group
        }
    });
    request.onResponseContent((theResponse, content) -> {
        // append content to group
    });
    request.onResponseSuccess(theResponse -> {
        log.debug(group.toString());
    });
    return request;
}

마지막으로 WebClient 인스턴스를 빌드해야 합니다.

WebClient
  .builder()
  .clientConnector(new JettyClientHttpConnector(httpClient))
  .build()

물론 이전과 마찬가지로  RequestLogEnhancer 의 로그 수준 을 DEBUG 로 설정해야 합니다 .

4.2. Netty HttpClient 로 로깅

먼저 Netty HttpClient 를 생성해 보겠습니다 .

HttpClient httpClient = HttpClient
  .create()
  .wiretap(true)

도청을 활성화하면 각 요청과 응답이 자세히 기록됩니다.

다음으로 Netty의 클라이언트 패키지 react.netty.http.client 의 로그 수준 을 DEBUG 로 설정해야 합니다 .

logging.level.reactor.netty.http.client=DEBUG

이제 WebClient 를 빌드해 보겠습니다 .

WebClient
  .builder()
  .clientConnector(new ReactorClientHttpConnector(httpClient))
  .build()

WebClient 는 모든 요청과 응답을 자세히 기록 하지만 Netty 내장 로거 기본 형식에는 본문의 Hex 및 Text 표현과 요청 및 응답 이벤트에 대한 많은 데이터가 포함되어 있습니다.

따라서 Netty용 텍스트 로거만 필요한 경우 HttpClient 를 구성할 수 있습니다 .

HttpClient httpClient = HttpClient
  .create()
  .wiretap("reactor.netty.http.client.HttpClient", 
    LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL);

5. 결론

이 사용방법(예제)에서는 Spring WebClient 를 사용하는 동안 요청 및 응답 데이터를 로깅하는 여러 기술을 사용했습니다 .

항상 그렇듯이 코드는 GitHub에서 사용할 수 있습니다 .

Generic footer banner