Spring REST Templates Accept Headers

During some load testing of one of our REST services, we begin to see these logs for the Spring REST template when the load increases:

With a simultaneous load and after 3-4 hours, the Accept header of the http request becomes

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>] 

Ultimately, all calls to this service using RestTemplate start with an error with a 400 error (incorrect request)

The called REST service accepts a String input and has the following signature

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

We send a POST request to this service with the contents of the request in the form of "someId", for example. "123"

With a low load, there is no problem calling the service.

What puzzles the text is text / plain, * / * , which is added to the list of accept headers for the REST template. Why is this happening?

The declaration of a REST bean template is as follows:

 <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> 

How the request is created:

 String postParams = "\"" + id + "\""; String postResp = restTemplate.postForObject("findRecordById",postParams, String.class); 
+5
source share
3 answers

In case someone comes here due to a repeating text / simple problem with the Accept header that the poster had, I experienced the same thing and this is what happened: We had the usual bean definition for the rest template in servlet-context. xml, where we specified the message converter for the / json application like this (this is for spring - beans 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> 

However, in the source code, we also explicitly added StringHttpMessageConverter using:

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

However, this MessageConverter list simply added a new instance of StringHttpMessageConverter for each request. For each request, Spring goes through this list of message converters and adds the corresponding Accept (text / plain) header. After so many requests, this leads to the length of the header increasing so much that it will be rejected by the container of the server that you are calling. The easiest way to fix this is to simply specify the / plain text as supported by MediaTypes in the servlet-context.xml file and delete the above line in the code. If you cannot do this, you need to put the check in the code to make sure that StringHttpMessageConverter is repeatedly added to the restTemplate instance.

Here's added servlet-context.xml with support for text / plainMediaType:

 <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> 
+1
source

Could you try:

 restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); String postParams = "\"" + id + "\""; String postResp = restTemplate.postForObject("findRecordById",postParams, String.class); 
0
source

text / plain was added because you are trying to read String and RestTemplate, found StringHttpMessageConverter as a converter for your request, and the supported media type for StringHttpMessageConverter is text / plain.

As you can see in this method 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); } } } } 
0
source

Source: https://habr.com/ru/post/1206216/


All Articles