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에서 사용할 수 있습니다 .