2010-07-23 34 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); 
      } 
     }); 
    } 
} 
相關問題