在对我们的一项REST服务进行负载测试期间,当负载增加时,我们开始看到Spring REST模板的以下类型的日志:

在并发负载下,经过3-4个小时,http请求的Accept header 变为

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服务发送POST类型的请求,请求内容的格式为“someId”,例如“123”

在轻负载下,调用服务没有问题。

令人困惑的是文本/纯文本*/* ,它们一直被添加到REST模板的接受 header 列表中。为什么会这样?

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

最佳答案

添加text/plain是因为您尝试读取String和RestTemplate,发现StringHttpMessageConverter作为您的请求的转换器,并且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);
                }
            }
        }
    }

10-07 18:55