我已经使用Spring RestTemplate有一段时间了,当我试图调试它的请求和响应时,我总是碰壁。我基本上希望看到与打开“verbose”选项时使用curl时相同的东西。例如:
curl -v http://twitter.com/statuses/public_timeline.rss
将显示发送的数据和接收的数据(包括头、cookie等)。
我看了一些相关的帖子,比如:
如何在Spring RestTemplate中记录响应?
但我还没能解决这个问题。
实现这一点的一种方法是实际更改RestTemplate源代码,并在那里添加一些额外的日志记录语句,但我认为这种方法确实是最后的办法。应该有某种方法告诉Spring Web Client/RestTemplate以一种更友好的方式记录所有内容。
我的目标是能够用如下代码做到这一点:
restTemplate.put("http://someurl", objectToPut, urlPathValues);
然后在日志文件或控制台中获得相同类型的调试信息(就像我使用curl获得的一样)。
我相信这对于任何使用Spring RestTemplate并且遇到问题的人来说都是非常有用的。使用curl来调试RestTemplate问题是行不通的(在某些情况下)。
我的日志记录器配置使用XML
<logger name="org.springframework.web.client.RestTemplate">
<level value="trace"/>
</logger>
然后你会得到如下内容:
DEBUG org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:92) : Reading [com.test.java.MyClass] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@604525f1]
通过HttpMessageConverterExtractor.java:92,你需要继续调试,在我的情况下,我得到了这个:
genericMessageConverter.write(requestBody, requestBodyType, requestContentType, httpRequest);
这:
outputMessage.getBody().flush();
outputMessage.getBody()包含http(post类型)发送的消息
您可以使用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。
免责声明:这个库是我写的。
正如@MilacH指出的,在实现中有一个错误。如果返回statusCode > 400,则从拦截器抛出IOException,因为没有调用errorHandler。可以忽略异常,然后在处理程序方法中再次捕获异常。
package net.sprd.fulfillment.common;
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;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import static java.nio.charset.StandardCharsets.UTF_8;
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {
final static Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
@SuppressWarnings("HardcodedLineSeparator")
public static final char LINE_BREAK = '\n';
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
try {
traceRequest(request, body);
} catch (Exception e) {
log.warn("Exception in LoggingRequestInterceptor while tracing request", e);
}
ClientHttpResponse response = execution.execute(request, body);
try {
traceResponse(response);
} catch (IOException e) {
// ignore the exception here, as it will be handled by the error handler of the restTemplate
log.warn("Exception in LoggingRequestInterceptor", e);
}
return response;
}
private void traceRequest(HttpRequest request, byte[] body) {
log.info("===========================request begin================================================");
log.info("URI : {}", request.getURI());
log.info("Method : {}", request.getMethod());
log.info("Headers : {}", request.getHeaders());
log.info("Request body: {}", new String(body, UTF_8));
log.info("==========================request end================================================");
}
private void traceResponse(ClientHttpResponse response) throws IOException {
StringBuilder inputStringBuilder = new StringBuilder();
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), UTF_8))) {
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
inputStringBuilder.append(LINE_BREAK);
line = bufferedReader.readLine();
}
}
log.info("============================response begin==========================================");
log.info("Status code : {}", response.getStatusCode());
log.info("Status text : {}", response.getStatusText());
log.info("Headers : {}", response.getHeaders());
log.info("Response body: {}", inputStringBuilder);
log.info("=======================response end=================================================");
}
}
用一些代码扩展@hstoerr answer:
创建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());