2014-11-05 83 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>