나는 Spring RestTemplate을 오랫동안 사용 해 왔으며 요청과 응답을 디버깅하려고 할 때 지속적으로 벽에 부딪쳤다. 나는 기본적으로 “verbose”옵션이 켜진 상태에서 curl을 사용할 때와 같은 것을보고자합니다. 예를 들면 다음과 같습니다.
curl -v http://twitter.com/statuses/public_timeline.rss
전송 된 데이터와 수신 된 데이터 (헤더, 쿠키 등 포함)를 모두 표시합니다.
다음과 같은 관련 게시물을 확인했습니다 :
Spring RestTemplate에서 응답을 어떻게 기록합니까?
하지만이 문제를 해결하지 못했습니다.
이를 수행하는 한 가지 방법은 실제로 RestTemplate 소스 코드를 변경하고 거기에 몇 가지 로깅 문을 추가하는 것이지만,이 방법은 실제로 최후의 수단이라는 것을 알 수 있습니다. Spring Web Client / RestTemplate에 모든 것을 훨씬 친숙한 방식으로 기록하도록 지시하는 방법이 있어야합니다.
내 목표는 다음과 같은 코드 로이 작업을 수행하는 것입니다.
restTemplate.put("http://someurl", objectToPut, urlPathValues);
그런 다음 로그 파일이나 콘솔에서 동일한 유형의 디버그 정보를 가져옵니다 (컬과 함께). Spring RestTemplate을 사용하고 문제가있는 사람에게는 이것이 매우 유용 할 것이라고 생각합니다. curl을 사용하여 RestTemplate 문제를 디버그하는 것은 효과가 없습니다 (경우에 따라).
답변
ClientHttpRequestInterceptor
요청과 응답을 추적하기 위한 전체 구현으로 예제를 완성하기 만하면됩니다 .
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {
final static Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
traceRequest(request, body);
ClientHttpResponse response = execution.execute(request, body);
traceResponse(response);
return response;
}
private void traceRequest(HttpRequest request, byte[] body) throws IOException {
log.info("===========================request begin================================================");
log.debug("URI : {}", request.getURI());
log.debug("Method : {}", request.getMethod());
log.debug("Headers : {}", request.getHeaders() );
log.debug("Request body: {}", new String(body, "UTF-8"));
log.info("==========================request end================================================");
}
private void traceResponse(ClientHttpResponse response) throws IOException {
StringBuilder inputStringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
inputStringBuilder.append('\n');
line = bufferedReader.readLine();
}
log.info("============================response begin==========================================");
log.debug("Status code : {}", response.getStatusCode());
log.debug("Status text : {}", response.getStatusText());
log.debug("Headers : {}", response.getHeaders());
log.debug("Response body: {}", inputStringBuilder.toString());
log.info("=======================response end=================================================");
}
}
그런 다음 RestTemplate
a BufferingClientHttpRequestFactory
와 LoggingRequestInterceptor
:를 사용하여 인스턴스화 하십시오 .
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new LoggingRequestInterceptor());
restTemplate.setInterceptors(interceptors);
BufferingClientHttpRequestFactory
인터셉터와 초기 호출 코드 모두에 응답 본문을 사용하려면 이 값 이 필요합니다. 기본 구현에서는 응답 본문을 한 번만 읽을 수 있습니다.
답변
Spring Boot에서는 속성 (또는 다른 12 요소 방법)에서 이것을 설정하여 전체 요청 / 응답을 얻을 수 있습니다
logging.level.org.apache.http=DEBUG
이 출력
-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connecting to localhost/127.0.0.1:41827
-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connection established 127.0.0.1:39546<->127.0.0.1:41827
-DEBUG o.a.http.impl.execchain.MainClientExec : Executing request POST /v0/users HTTP/1.1
-DEBUG o.a.http.impl.execchain.MainClientExec : Target auth state: UNCHALLENGED
-DEBUG o.a.http.impl.execchain.MainClientExec : Proxy auth state: UNCHALLENGED
-DEBUG org.apache.http.headers : http-outgoing-0 >> POST /v0/users HTTP/1.1
-DEBUG org.apache.http.headers : http-outgoing-0 >> Content-Type: application/json;charset=UTF-8
-DEBUG org.apache.http.headers : http-outgoing-0 >> Content-Length: 56
-DEBUG org.apache.http.headers : http-outgoing-0 >> Host: localhost:41827
-DEBUG org.apache.http.headers : http-outgoing-0 >> Connection: Keep-Alive
-DEBUG org.apache.http.headers : http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)
-DEBUG org.apache.http.headers : http-outgoing-0 >> Accept-Encoding: gzip,deflate
-DEBUG org.apache.http.wire : http-outgoing-0 >> "POST /v0/users HTTP/1.1[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Content-Length: 56[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Host: localhost:41827[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "{"id":null,"email":"xenoterracide@gmail.com","new":true}"
그리고 응답
-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connecting to localhost/127.0.0.1:41827
-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connection established 127.0.0.1:39546<->127.0.0.1:41827
-DEBUG o.a.http.impl.execchain.MainClientExec : Executing request POST /v0/users HTTP/1.1
-DEBUG o.a.http.impl.execchain.MainClientExec : Target auth state: UNCHALLENGED
-DEBUG o.a.http.impl.execchain.MainClientExec : Proxy auth state: UNCHALLENGED
-DEBUG org.apache.http.headers : http-outgoing-0 >> POST /v0/users HTTP/1.1
-DEBUG org.apache.http.headers : http-outgoing-0 >> Content-Type: application/json;charset=UTF-8
-DEBUG org.apache.http.headers : http-outgoing-0 >> Content-Length: 56
-DEBUG org.apache.http.headers : http-outgoing-0 >> Host: localhost:41827
-DEBUG org.apache.http.headers : http-outgoing-0 >> Connection: Keep-Alive
-DEBUG org.apache.http.headers : http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)
-DEBUG org.apache.http.headers : http-outgoing-0 >> Accept-Encoding: gzip,deflate
-DEBUG org.apache.http.wire : http-outgoing-0 >> "POST /v0/users HTTP/1.1[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Content-Length: 56[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Host: localhost:41827[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "[\r][\n]"
-DEBUG org.apache.http.wire : http-outgoing-0 >> "{"id":null,"email":"xenoterracide@gmail.com","new":true}"
또는 logging.level.org.apache.http.wire=DEBUG
관련 정보가 모두 포함 된 것 같습니다
답변
일부 코드로 @hstoerr 답변을 확장 :
요청 응답을 기록하는 LoggingRequestInterceptor 작성
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
log(request,body,response);
return response;
}
private void log(HttpRequest request, byte[] body, ClientHttpResponse response) throws IOException {
//do logging
}
}
RestTemplate 설정
RestTemplate rt = new RestTemplate();
//set interceptors/requestFactory
ClientHttpRequestInterceptor ri = new LoggingRequestInterceptor();
List<ClientHttpRequestInterceptor> ris = new ArrayList<ClientHttpRequestInterceptor>();
ris.add(ri);
rt.setInterceptors(ris);
rt.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
답변
가장 좋은 방법은 파일 에 추가 logging.level.org.springframework.web.client.RestTemplate=DEBUG
하는 것 application.properties
입니다.
설정과 같은 다른 솔루션 log4j.logger.httpclient.wire
은 항상 사용 하지 않고 log4j
Apache 를 사용한다고 가정하기 때문에 항상 작동 HttpClient
하지는 않습니다.
그러나이 구문은 최신 버전의 Spring Boot에서만 작동합니다.
답변
이 답변 중 어느 것도 실제로 문제의 100 %를 해결하지 못합니다. mjj1409는 대부분을 얻지 만 응답 로깅 문제를 편리하게 피할 수 있으므로 조금 더 많은 작업이 필요합니다. Paul Sabou는 현실적으로 보이지만 실제로 구현하기에 충분한 세부 정보를 제공하지 않는 솔루션을 제공합니다 (나에게 전혀 효과가 없었습니다). Sofiene은 로깅을 얻었지만 중요한 문제가 있습니다. 입력 스트림이 이미 소비되었으므로 응답을 더 이상 읽을 수 없습니다!
응답 본문을 여러 번 읽을 수 있도록 BufferingClientHttpResponseWrapper를 사용하여 응답 객체를 래핑하는 것이 좋습니다.
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
response = log(request, body, response);
return response;
}
private ClientHttpResponse log(final HttpRequest request, final byte[] body, final ClientHttpResponse response) {
final ClientHttpResponse responseCopy = new BufferingClientHttpResponseWrapper(response);
logger.debug("Method: ", request.getMethod().toString());
logger.debug("URI: ", , request.getURI().toString());
logger.debug("Request Body: " + new String(body));
logger.debug("Response body: " + IOUtils.toString(responseCopy.getBody()));
return responseCopy;
}
}
응답 본문이 메모리에로드되어 여러 번 읽을 수 있기 때문에 InputStream을 사용하지 않습니다. 클래스 경로에 BufferingClientHttpResponseWrapper가없는 경우 여기에서 간단한 구현을 찾을 수 있습니다.
RestTemplate을 설정하려면 다음을 수행하십시오.
LoggingRequestInterceptor loggingInterceptor = new LoggingRequestInterceptor();
restTemplate.getInterceptors().add(loggingInterceptor);
답변
spring-rest-template-logger 를 사용하여 RestTemplate
HTTP 트래픽 을 기록 할 수 있습니다 .
Maven 프로젝트에 종속성을 추가하십시오.
<dependency>
<groupId>org.hobsoft.spring</groupId>
<artifactId>spring-rest-template-logger</artifactId>
<version>2.0.0</version>
</dependency>
그런 RestTemplate
다음 다음과 같이 사용자 정의하십시오 .
RestTemplate restTemplate = new RestTemplateBuilder()
.customizers(new LoggingCustomizer())
.build()
다음에서 디버그 로깅이 사용 가능한지 확인하십시오 application.properties
.
logging.level.org.hobsoft.spring.resttemplatelogger.LoggingCustomizer = DEBUG
이제 모든 RestTemplate HTTP 트래픽이 org.hobsoft.spring.resttemplatelogger.LoggingCustomizer
디버그 수준 .
면책 조항 : 나는이 도서관을 썼습니다.
답변
xenoterracide가 제공하는 솔루션
logging.level.org.apache.http=DEBUG
좋지만 문제는 기본적으로 Apache HttpComponents가 사용되지 않는다는 것입니다.
Apache HttpComponents를 사용하려면 pom.xml에 추가하십시오.
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
</dependency>
다음과 같이 구성하십시오 RestTemplate
.
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsAsyncClientHttpRequestFactory());
