HttpMessageNotReadableException:JSON 解析错误:VALUE_STRING 中出现意外的输入结束

问题描述 投票:0回答:1

当我升级到 3.2.5 版本时,我们在 3.1.0 版本上有 Spring boot 微服务,带有 Rest 模板的 POST 请求开始失败并抛出以下异常 org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected end-of - 输入 VALUE_STRING。我对比了版本升级前后的JSON数据和httpHeaders,没有发现任何差异。我仍然无法弄清楚这里的实际问题是什么?还有其他人面临同样的问题吗?

技术: 爪哇17 Spring引导版本3.2.5 httpclient5 版本 - 5.3.1 Netty 处理程序版本 - 4.1.109.Final

将 Spring boot 版本从 3.1.0 升级到 3.2.5 后,使用剩余模板的 POST Api 调用会抛出 400 错误请求,我需要修复此问题

package com.ual.xclr.common.config;

import com.ual.xclr.common.interceptor.RestTemplateReqResLoggingInterceptor;
import com.ual.xclr.common.utility.XclrUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.core5.util.Timeout;
//import org.apache.http.impl.client.HttpClients;
//import org.apache.http.impl.client.HttpClientBuilder;
//import org.apache.http.impl.client.CloseableHttpClient;
//import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
//import org.apache.http.client.config.RequestConfig;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;

@Configuration
@Slf4j
public class RestTemplateConfig {
    @Value("${restTemplateDefaultConnectionTimeOut:600000}") // 10 Min
    private int restTemplateDefaultConnectionTimeOut;

    @Value("${restTemplateDefaultReadTimeOut:600000}")
    private int restTemplateDefaultReadTimeOut;


    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Primary
    public RestTemplate getRestTemplate(RestTemplateBuilder builder) {
        RestTemplate restTemplate = builder.requestFactory(this::getClientHttpRequestFactory)
                .interceptors(new RestTemplateReqResLoggingInterceptor())
                .build();
        return restTemplate;
    }

    private BufferingClientHttpRequestFactory getClientHttpRequestFactory() {
        try {
            TrustStrategy acceptingTrustStrategy = (X509Certificate[] x509Certificates, String s) -> true;

            SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
                    .build();

            SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
            HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
                    .setSSLSocketFactory(csf)
                    .build();

            CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();

            HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory();
            httpFactory.setConnectTimeout(restTemplateDefaultConnectionTimeOut);
            httpFactory.setConnectionRequestTimeout(restTemplateDefaultConnectionTimeOut);
            httpFactory.setHttpClient(httpClient);

            return new BufferingClientHttpRequestFactory(httpFactory);
        } catch (Exception e) {
            log.error("There is an exception in creating RestTemplate i.e. -{}", XclrUtils.crlfInjectionNeutralizer(e, true, true));
            return null; // You might want to handle this differently based on your use case
        }
    }

}

Rest 模板调用抛出 400 错误请求

try {
    httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
    httpHeaders.setContentType(MediaType.valueOf("application/json;charset=UTF-8"));
    String xclradaptercargomailpublishurl = adapterMSKUrl + "/publishCargoMailEvent";
    String compositeKey = null;
    if (httpHeaders.containsKey(AppConstants.OPS_FLT_NBR)) {
        StringBuilder stringBuilder = new StringBuilder();
        compositeKey = stringBuilder.append(UAX_CHECKOUT_MAIL_ACK).append(AppConstants.DoubleColon)
                .append(httpHeaders.get(AppConstants.OPS_CARR_IATA_CD).get(0)).append(AppConstants.DoubleColon)
                .append(httpHeaders.get(AppConstants.OPS_FLT_NBR).get(0)).append(AppConstants.DoubleColon)
                .append(httpHeaders.get(AppConstants.FLT_LEG_DEP_DT).get(0)).append(AppConstants.DoubleColon)
                .append(httpHeaders.get(AppConstants.OPS_LEG_DEP_ARPT_IATA_CD).get(0))
                .append(AppConstants.DoubleColon)
                .append(httpHeaders.get(AppConstants.OPS_LEG_ARR_ARPT_IATA_CD).get(0))
                .append(AppConstants.DoubleColon).append(httpHeaders.get(AppConstants.ORIG_OCCUR_NBR).get(0))
                .toString();
    }
    XCLRMsg xclrMsg = new XCLRMsg();
    xclrMsg.setKey(compositeKey);
    String message = XclrUtils.convertJavaObjectToJson(cargoMailAckMessage);
    log.info("Safwan Testing cargomailmsg {}",message);
    xclrMsg.setMessage(message);
    HttpEntity<XCLRMsg> entity = new HttpEntity<>(xclrMsg, httpHeaders);
    log.info("Safwan Testing xclrmsgobj {}",xclrMsg);
    log.info("Safwan Testing HttpEntity {}",entity);
    restTemplate.exchange(xclradaptercargomailpublishurl, HttpMethod.POST, entity, String.class);
} catch (Exception e) { // NOSONAR
    log.error("Could not publish acknowledgment to CargoMail topic - {} for headers {}", XclrUtils.crlfInjectionNeutralizer(e,true,true),XclrUtils.sanitizeHttpHeadersForLogging(httpHeaders));
}
spring-boot httpclient resttemplate java-17 400-bad-request
1个回答
0
投票

找到了解决方案,在新的 Spring boot 版本 3.2.5 中,内容长度会自动添加到 httpHeaders 中,并且 API 调用失败并抛出 400 BAD 请求。我在每次 API 调用之前通过 Rest 模板添加了以下代码,这解决了问题

httpHeaders.remove("content-length");
© www.soinside.com 2019 - 2024. All rights reserved.