我已经使用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问题是行不通的(在某些情况下)。


当前回答

用一些代码扩展@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());

其他回答

最好的方法是向应用程序添加loggging.level.org.springframework.web.client.resttemplate =DEBUG。属性文件。

其他解决方案,如设置log4j.logger.httpclient。wire不会总是工作,因为它们假设您使用log4j和Apache HttpClient,这并不总是正确的。

但是请注意,此语法仅适用于最新版本的Spring Boot。

所给出的溶液由异种杀菌剂使用

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());

用一些代码扩展@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());

wire提供了太多不可读的日志,所以我使用日志记录应用程序Servlet和RestTemplate请求和响应的有效负载。

build.gradle:

compile group: 'org.zalando', name: 'logbook-spring-boot-starter', version: '2.6.2'

或Maven依赖:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-spring-boot-starter</artifactId>
    <version>2.6.2</version>
</dependency>

应用程序。属性(或槽YAML):

logging.level.org.zalando.logbook = TRACE

RestTemplate.java:

import java.util.function.Supplier;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.zalando.logbook.httpclient.LogbookHttpRequestInterceptor;
import org.zalando.logbook.httpclient.LogbookHttpResponseInterceptor;

@Configuration
public class RestTemplateConfiguration {
    private final LogbookHttpRequestInterceptor logbookHttpRequestInterceptor;
    private final LogbookHttpResponseInterceptor logbookHttpResponseInterceptor;

    public RestTemplateConfiguration(LogbookHttpRequestInterceptor logbookHttpRequestInterceptor,
            LogbookHttpResponseInterceptor logbookHttpResponseInterceptor) {
        this.logbookHttpRequestInterceptor = logbookHttpRequestInterceptor;
        this.logbookHttpResponseInterceptor = logbookHttpResponseInterceptor;
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder
                .requestFactory(new MyRequestFactorySupplier())
                .build();
    }

    class MyRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {
        @Override
        public ClientHttpRequestFactory get() {
            // Using Apache HTTP client
            CloseableHttpClient client = HttpClientBuilder.create()
                    .addInterceptorFirst(logbookHttpRequestInterceptor)
                    .addInterceptorFirst(logbookHttpResponseInterceptor)
                    .build();
            return new HttpComponentsClientHttpRequestFactory(client);
        }
    }
}

我浏览了所有的答案,如果你需要设置认证类型或连接超时,那么你可以这样做:

SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(Integer.valueOf(YOUR_VALUE));
factory.setReadTimeout(Integer.valueOf(YOUR_VALUE));

RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(factory));
restTemplate.getInterceptors().add(new LoggingRequestInterceptor());
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(USER_NAME,PASSWORD,StandardCharsets.UTF_8));
return restTemplate;