2014-11-05 3 views
5

В течение некоторого нагрузочного тестирования одного из наших REST услуг, мы начинаем видеть такого рода журналы для шаблона REST Spring, когда нагрузка возрастает:Spring REST шаблон принимает заголовки

При одновременной нагрузке и после 3-4 часов, Принять заголовок запроса HTTP становится

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 Error (Bad Request)

службы REST называют принимает строку в качестве входных данных и имеет следующий Signatur e

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

Мы отправляем запрос типа POST этой службе с запросом содержимого формы «someId», например. «123»

При низкой нагрузке при вызове службы не возникает никаких проблем.

Что вызывает недоумение - текст , */*, которые продолжают добавляться в список принимающих заголовков для шаблона REST. Почему это происходит?

Объявление шаблона боб REST, как это:

<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' .. –

+0

редактировал вопрос, чтобы показать, как запрос сделан –

+0

Итак, вы получаете 'restTemplate' непосредственно из' ApplicationContext' без каких-либо дополнительных изменений? И вы отправляете тонны запроса, как указано выше? –

ответ

0

Не могли бы вы попробовать это:

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

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

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

. Я вижу, что конструктор уже добавляет этот конвертер сообщений. Не похоже, что это может вызвать проблемы. –

0

текст/обычный добавляется, потому что вы пытаетесь прочитать String и RestTemplate, нашли StringHttpMessageConverter в качестве конвертера для вашего запроса, а поддерживаемый тип носителя для StringHttpMessageConverter - текстовый/обычный.

Как вы можете видеть в этом методе 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

В случае кто приходит сюда из-за неоднократный текст/равниной Accept проблемы заголовка, что плакат был, я испытал то же самое, и вот что происходит: Мы имели наше обычное определение бин для шаблона отдыха в сервлет-context.xml, где мы указали сообщение конвертер для приложения/JSON как так (это для пружинной фасоли 4.0):

<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 с помощью:

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

Однако это сообщениеConverter list просто добавляло к нему новый экземпляр StringHttpMessageConverter по каждому запросу. Для каждого запроса Spring проходит через этот список конвертеров сообщений и добавляет соответствующий заголовок Accept (text/plain). После стольких запросов это приводит к тому, что длина заголовка увеличивается настолько, что он будет отклонен контейнером сервера, который вы вызываете. Самый простой способ исправить это - просто указать текст/plain как поддерживаемыйMediaTypes в файле servlet-context.xml и удалить указанную выше строку в коде. Если вы не можете этого сделать, вам нужно поместить чек в код, чтобы убедиться, что StringHttpMessageConverter неоднократно добавляется к экземпляру restTemplate.

Вот сервлет-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>