Spring-boot的RestTemplate显示响应体为空,但拦截器明确显示有响应体。

7

在使用Spring-boot 1.5.10.RELEASE时,我得到的response.body为null。

以下是我如何使用RestTemplate:

RestTemplate restTemplate = new RestTemplate();
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new LoggingRequestInterceptor());
    restTemplate.setInterceptors(interceptors);

    String url = "http://someurl/Commands";

    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("cmd", "{\"operation\":\"getSomeDetails\"}}");

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);

    ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);

    System.out.println("This is always null: " + response.getBody());

虽然上面的程序总是打印null,但是下面的拦截器打印有效的响应正文。
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

final static Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
                                    final ClientHttpRequestExecution execution) throws IOException {
    traceRequest(request, body);
    ClientHttpResponse response = execution.execute(request, body);
    traceResponse(response);
    return response;
}


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.debug("============================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.debug("=======================response end=================================================");
}

}

5个回答

20
尽管已有接受的答案说明了原因,但我认为解决方案也是必要的。
Spring提供了一个BufferingClientHttpRequestFactory,作为Rest Template默认的SimpleClientHttpRequestFactory的包装器。创建Rest Template时可以将其传递给它。这将强制Rest Template使用响应的副本而不是销毁它,以使拦截器能够使用它。
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());

RestTemplate restTemplate = new RestTemplate(factory);

来源: http://objectpartners.com/2018/03/01/log-your-resttemplate-request-and-response-without-destroying-the-body/


9
你正在使用traceResponse消费响应体,这就是你的问题所在。同时,请更新你的问题并让它更加具体;“最新的”是含糊不清的。今天最新的可能明天就不再是了。

非常感谢你,Abhijit! - Yogesh Manware

1

在搜索了一段时间后,我尝试使用HttpComponentsClientHttpRequestFactory()代替SimpleClientHttpRequestFactory()。

ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory());

这对我解决了问题。


说明:本文提到的是IT技术相关内容,建议读者具备一定的专业背景知识。

1
下面的代码将解决问题。
@Bean public RestTemplate restTemplate() {
final RestTemplate restTempate = new RestTemplate(new BufferingClientHttpRequestFactory(new
                  SimpleClientHttpRequestFactory()));
final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new LogHttpInterceptor());
restTempate.setInterceptors(interceptors);
return restTemplate;}

日志拦截器将会像下面这样:
public class LogHttpInterceptor implements ClientHttpRequestInterceptor {

final static Logger log = LoggerFactory.getLogger(LogHttpInterceptor.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");
}

如果不起作用,请告诉我


0

按照以下方式创建您的RestTemplate

@Bean
    public RestTemplate interceptedRestTemplate() {
        RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(
                new SimpleClientHttpRequestFactory()
        ));
        restTemplate.setInterceptors(List.of(<i>your interceptor</i>));
        return restTemplate;
    }

对我有用。


我不知道你的问题是什么意思,我的意思是一个人问了一个关于他/她的问题,我给出了我曾经用过的具体解决方案,这对你有什么特别之处吗? - JovoH
我的意思是,你没有解释为什么它能够工作,只是说它工作了。就像“授人以鱼不如授人以渔”一样。 - Abhijit Sarkar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接