2014-11-05 64 views
5

在我們的REST服務之一的一些負載測試中,我們開始看到這幾樣的日誌,用於Spring的REST模板當負載增加時:彈簧安置模板接受頭

下一個併發負載和3-4小時後, http請求的Accept報頭變得

DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, application/json, application/*+json, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain, text/plain,<and so on>, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, */*, <and so on>] 

最終所有的呼叫,使用RestTemplate開始400錯誤(錯誤的請求)未

被調用時的REST服務接受字符串作爲輸入,並具有以下這種服務簽名

@RequestMapping(value = "/findRecordById", method = {RequestMethod.POST, RequestMethod.GET }) 
@ResponseBody 
public String findRecordById(@RequestBody String id) {//method body} 

我們發送POST類型的請求到這個服務,請求內容形式爲「someId」,例如, 「123」

在輕負載下,在調用服務時沒有問題。

最讓人費解的是text/plain,*/*,它們不斷被添加到REST模板的接受標頭列表中。爲什麼會發生?

其餘模板bean聲明是這樣的:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> 
     <constructor-arg> 
      <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"> 
       <property name="readTimeout"> 
        <value>90000</value> 
       </property> 
       <property name="httpClient" ref="restHttpClient" /> 
      </bean> 
     </constructor-arg> 
    </bean> 

    <bean id="restHttpClient" class="org.apache.http.impl.client.DefaultHttpClient"> 
      <constructor-arg> 
      <bean class="org.apache.http.impl.conn.PoolingClientConnectionManager"> 
       <property name="defaultMaxPerRoute"> 
        <value>100000</value> 
       </property> 
       <property name="maxTotal"> 
        <value>100000</value> 
       </property>     

      </bean> 
      </constructor-arg> 
    </bean> 

被如何創建請求:

String postParams = "\"" + id + "\""; 

String postResp = restTemplate.postForObject("findRecordById",postParams, String.class); 
+1

請告訴我們您做用'RestTemplate'的請求的例子.. – 2014-11-05 02:16:03

+0

編輯的問題來說明如何請求是 – 2014-11-05 03:04:04

+0

所以你直接從'ApplicationContext'獲得'restTemplate'而沒有額外的修改?你發送像上面這麼多的請求嗎? – 2014-11-05 03:22:28

回答

0

能否請您試試這個:

restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); 

String postParams = "\"" + id + "\""; 

String postResp = restTemplate.postForObject("findRecordById",postParams, String.class); 
+0

我看到構造函數已經添加了這個消息轉換器。看起來不像這可能導致問題。 – 2014-11-05 05:59:27

0

純文本/是因爲你嘗試讀取一個字符串和RestTemplate,發現StringHttpMessageConverter作爲你的r轉換器equest,並且StringHttpMessageConverter支持的媒體類型爲text/plain。

正如您在RestTemplate的這種方法中所看到的那樣。

public void doWithRequest(ClientHttpRequest request) throws IOException { 
      if (responseType != null) { 
       List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); 
       for (HttpMessageConverter<?> messageConverter : getMessageConverters()) { 
        if (messageConverter.canRead(responseType, null)) { 
         List<MediaType> supportedMediaTypes = messageConverter.getSupportedMediaTypes(); 
         for (MediaType supportedMediaType : supportedMediaTypes) { 
          if (supportedMediaType.getCharSet() != null) { 
           supportedMediaType = 
             new MediaType(supportedMediaType.getType(), supportedMediaType.getSubtype()); 
          } 
          allSupportedMediaTypes.add(supportedMediaType); 
         } 
        } 
       } 
       if (!allSupportedMediaTypes.isEmpty()) { 
        MediaType.sortBySpecificity(allSupportedMediaTypes); 
        if (logger.isDebugEnabled()) { 
         logger.debug("Setting request Accept header to " + allSupportedMediaTypes); 
        } 
        request.getHeaders().setAccept(allSupportedMediaTypes); 
       } 
      } 
     } 
    } 
1

萬一有人來,因爲重複的文字在這裏/平接受頭問題的海報有,我經歷了同樣的事情,這裏發生了什麼事: 我們有我們常用的bean定義在休息模板

<beans:bean id="myRestTemplate" class="com.mypackage.MyClass"> 
     <beans:property name="requestFactoryNonSSL" ref="restTemplateNonSSLRequestFactory"/> 
     <beans:property name="requestFactorySSL" ref="restTemplateNonSSLRequestFactory"/> 
     <beans:property name="messageConverters"> 
      <beans:list> 
       <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter"> 
        <beans:property name="supportedMediaTypes"> 
         <beans:list> 
          <beans:value>application/json;charset=UTF-8</beans:value> 
         </beans:list> 
        </beans:property> 
       </beans:bean>   
      </beans:list> 
     </beans:property> 
    </beans:bean> 

然而,在源代碼中我們也被明確添加使用StringHttpMessageConverter:

我們指定的消息轉換爲應用/ JSON像這樣(在此爲彈簧豆4.0)servlet的context.xml中
restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); 

但是,這個messageConverter列表剛剛得到一個新的StringHttpMessageConverter實例添加到它的每一個請求。對於每個請求,Spring都通過該消息轉換器列表並添加相應的Accept頭(文本/純文本)。經過這麼多的請求後,這會導致頭部長度變得很大,以至於被調用的服務器容器拒絕。解決這個問題的最簡單方法是在servlet-context.xml中將文本/ plain指定爲supportedMediaTypes,並在代碼中刪除上面的行。 如果你不能這樣做,你需要在代碼中進行檢查,以確保StringHttpMessageConverter不會重複添加到restTemplate實例中。

這裏的servlet的context.xml中使用純文本/ supportedMediaType補充說:

<beans:bean id="myRestTemplate" class="com.mypackage.MyClass"> 
     <beans:property name="requestFactoryNonSSL" ref="restTemplateNonSSLRequestFactory"/> 
     <beans:property name="requestFactorySSL" ref="restTemplateNonSSLRequestFactory"/> 
     <beans:property name="messageConverters"> 
      <beans:list> 
       <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter"> 
        <beans:property name="supportedMediaTypes"> 
         <beans:list> 
          <beans:value>application/json;charset=UTF-8</beans:value> 
          <beans:value>text/plain</beans:value> 
         </beans:list> 
        </beans:property> 
       </beans:bean>   
      </beans:list> 
     </beans:property> 
    </beans:bean>