2010-07-23 91 views
17

好吧,我有一个NamedSystems类,它有唯一字段为NamedSystem集。Spring RestTemplate在处理状态为NO_CONTENT的响应时的行为

我有一种方法可以通过某些标准来查找NamedSystems。这并不重要。当它得到结果时,一切正常。然而,当它找不到任何东西,并因此返回一个null(或者空 - 我已经尝试了两种方式)set,我会遇到问题。让我解释。

我使用了Spring RestTemplate类,我在单元测试做这样的呼吁:现在

ResponseEntity<?> responseEntity = template.exchange(BASE_SERVICE_URL + "? 
    alias={aliasValue}&aliasAuthority={aliasAssigningAuthority}", 
    HttpMethod.GET, makeHttpEntity("xml"), NamedSystems.class, 
    alias1.getAlias(), alias1.getAuthority()); 

,因为这通常会返回一个200,但我想返回一个204 ,我的服务中有一个拦截器,用于确定ModelAndView是否是NamedSystem,并且它的集合是否为null。如果是这样,那么我将状态码设置为NO_CONTENT(204)。

当我运行我的JUnit测试,我得到这个错误:

org.springframework.web.client.RestClientException: Cannot extract response: no Content-Type found 

设置状态NO_CONTENT似乎擦内容类型字段(其中有一定道理的时候,我认为这件事)。那为什么它看起来呢?

Spring的HttpMessageConverterExtractor ExtractData由方法:

public T extractData(ClientHttpResponse response) throws IOException { 
    MediaType contentType = response.getHeaders().getContentType(); 
    if (contentType == null) { 
     throw new RestClientException("Cannot extract response: no Content-Type found"); 
    } 
    for (HttpMessageConverter messageConverter : messageConverters) { 
     if (messageConverter.canRead(responseType, contentType)) { 
      if (logger.isDebugEnabled()) { 
       logger.debug("Reading [" + responseType.getName() + "] as \"" + contentType 
        +"\" using [" + messageConverter + "]"); 
      } 
      return (T) messageConverter.read(this.responseType, response); 
     } 
    } 
    throw new RestClientException(
     "Could not extract response: no suitable HttpMessageConverter found for response type [" + 
     this.responseType.getName() + "] and content type [" + contentType + "]"); 
} 

涨升链中的一个位,找出该提取设置,我对RestTemplate的交换来了()的方法,我在测试中使用:

public <T> ResponseEntity<T> exchange(String url, HttpMethod method, 
    HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException { 
    HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType); 
    ResponseEntityResponseExtractor<T> responseExtractor = new ResponseEntityResponseExtractor<T>(responseType); 
    return execute(url, method, requestCallback, responseExtractor, uriVariables); 
} 

因此,它试图将交换呼叫中提供的响应类型转换为无。如果我将NamedSystems.class的responseType更改为null,它将按预期工作。它不会尝试转换任何东西。如果我试图将状态码设置为404,它也可以正常执行。

我被误导了,还是这看起来像RestTemplate中的一个缺陷?当然,我现在在使用junit,所以我知道会发生什么,但是如果有人使用RestTemplate调用此函数并且不知道服务调用的结果,他们自然会将NamedSystems作为响应类型。但是,如果他们尝试了一个没有元素的标准搜索,他们会有这个令人讨厌的错误。

有没有解决这个问题的方法,而不重写任何RestTemplate的东西?我是否错误地查看了这种情况?请帮忙,因为我有点困惑。

+0

我现在正在处理这个问题。你有没有想出任何解决方案? – Fil 2011-03-17 16:20:13

+0

不是。这对我们来说不是什么大问题,因为我们只在junit中使用RestTemplate,所以我们只需将该类设置为null即可。看起来下面的答案可能会帮助你。你应该在下面的春季jira增强请求上投票。 – AHungerArtist 2011-03-17 20:08:57

+0

我差不多在同一条船上,使用RestTemplate进行单元测试。没有什么大不了的,但我肯定会对这个提升进行投票。 – Fil 2011-03-18 13:01:11

回答

1

我认为你是对的。 我有类似的问题。 我想我们应该得到一个带有NO_CONTENT和空体的HttpStatus的ResponseEntity。

+0

我同意你的意见。我也看到了这一点。 – 2011-03-02 17:00:53

10

我相信你应该看看ResponseExtractor接口&呼叫在RestTemplate提供您的抽取器实现执行。对我来说,它看起来像一个共同的要求做,所以都记录在此:

https://jira.springsource.org/browse/SPR-8016

这里有一个我准备早:

private class MyResponseExtractor extends HttpMessageConverterExtractor<MyEntity> { 

    public MyResponseExtractor (Class<MyEntity> responseType, 
     List<HttpMessageConverter<?>> messageConverters) { 
     super(responseType, messageConverters); 
    } 

    @Override 
    public MyEntity extractData(ClientHttpResponse response) throws IOException { 

     MyEntity result; 

     if (response.getStatusCode() == HttpStatus.OK) { 
      result = super.extractData(response); 
     } else { 
      result = null; 
     } 

     return result; 
    } 
} 

我测试过这个&似乎做什么,我想。

要创建ResponseExtractor的实例,我调用构造函数&从已注入的RestTemplate实例传递转换器;

E.g.

ResponseExtractor<MyEntity> responseExtractor = 
    new MyResponseExtractor(MyEntity.class, restTemplate.getMessageConverters()); 

接着,电话是:

MyEntity responseAsEntity = 
    restTemplate.execute(urlToCall, HttpMethod.GET, null, responseExtractor); 

您的里程可能会有所不同。 ;-)

+1

如果用普通的 – Zarathustra 2015-04-01 09:18:19

9

解决此问题的另一种方法是将响应实体设置为null,如下所示。

ResponseEntity<?> response = restTemplate.exchange("http://localhost:8080/myapp/user/{userID}", 
                  HttpMethod.DELETE, 
                  requestEntity, 
                  null, 
                  userID); 

如果您仍然需要响应头,请尝试实现ResponseErrorHandler。

+0

替换MyEnttity,这可能会更通用我已经使用restTemplate这种方式用于需要响应状态值(甚至是成功)的PUT和DELETE调用,并且它工作正常。 – 2012-02-17 14:23:17

+0

这很好。谢谢。 – 2017-09-12 06:08:22

1

或者您可以扩展RestTemplate并覆盖doExecute(..)并检查响应正文。

例如这里是我实现,为我们工作:

@Override 
protected <T> T doExecute(final URI url, final HttpMethod method, final RequestCallback requestCallback, final ResponseExtractor<T> responseExtractor) 
     throws RestClientException 
{ 
    Assert.notNull(url, "'url' must not be null"); 
    Assert.notNull(method, "'method' must not be null"); 
    ClientHttpResponse response = null; 
    try 
    { 
     final ClientHttpRequest request = createRequest(url, method); 
     if (requestCallback != null) 
     { 
      requestCallback.doWithRequest(request); 
     } 
     response = request.execute(); 
     if (!getErrorHandler().hasError(response)) 
     { 
      logResponseStatus(method, url, response); 
     } 
     else 
     { 
      handleResponseError(method, url, response); 
     } 
     if ((response.getBody() == null) || (responseExtractor == null)) 
     { 
      return null; 
     } 
     return responseExtractor.extractData(response); 
    } 
    catch (final IOException ex) 
    { 
     throw new ResourceAccessException("I/O error: " + ex.getMessage(), ex); 
    } 
    finally 
    { 
     if (response != null) 
     { 
      response.close(); 
     } 
    } 
} 
+1

这现在应该在Spring 3.1 RC1中修复。 https://jira.springsource.org/browse/SPR-7911 – AHungerArtist 2012-06-12 18:27:16

6

这里有一个简单的解决方案,你可以,如果它在响应丢失设置默认的Content-Type使用。 Content-Type被添加到响应头中,然后返回到预配置的ResponseExtractor进行提取。

public class CustomRestTemplate extends RestTemplate { 

    private MediaType defaultResponseContentType; 

    public CustomRestTemplate() { 
     super(); 
    } 

    public CustomRestTemplate(ClientHttpRequestFactory requestFactory) { 
     super(requestFactory); 
    } 

    public void setDefaultResponseContentType(String defaultResponseContentType) { 
     this.defaultResponseContentType = MediaType.parseMediaType(defaultResponseContentType); 
    } 

    @Override 
    protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, final ResponseExtractor<T> responseExtractor) 
      throws RestClientException { 

     return super.doExecute(url, method, requestCallback, new ResponseExtractor<T>() { 
      public T extractData(ClientHttpResponse response) throws IOException { 
       if (response.getHeaders().getContentType() == null && defaultResponseContentType != null) { 
        response.getHeaders().setContentType(defaultResponseContentType); 
       } 

       return responseExtractor.extractData(response); 
      } 
     }); 
    } 
} 
相关问题