RestTemplate未返回完整XML响应问题排查求助
问题:Spring Boot RestTemplate调用XML接口缺失
<revenueAccessorialList>元素 用Spring Boot调用返回XML格式的REST服务时,Postman能拿到完整的XML响应,但用RestTemplate的exchange或postForEntity方法调用时,<revenueAccessorialList>元素(包括第一个有效项和两个标记为xsi:nil="true"的空元素)全部缺失。求解决办法,以及除了RestTemplate之外的替代方案。
示例XML响应
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <RateResponse> <RateQueryResponses> <rateQueryResponseList> <carrierCode>CUST</carrierCode> <mode>SLTL</mode> < ... more content here .... > <declaredValue>0.0</declaredValue> <routingGuideLane> <destLocType></destLocType> <frequency></frequency> <laneDest></laneDest> <origLocType></origLocType> </routingGuideLane> <routingGuideLaneCarrierDetails> <capacityVolume>0</capacityVolume> <carrierCode>CUST</carrierCode> <rank></rank> <tier></tier> </routingGuideLaneCarrierDetails> <totalRevenue> <rate>0.0</rate> <revenueAccessorialList> <accessorialCode>FUEL</accessorialCode> <accessorialRevenue>0.0</accessorialRevenue> <approved>true</approved> <calculationMethod>PCT</calculationMethod> <minimumRate>0.0</minimumRate> <payeeCarrierId>-2147483648</payeeCarrierId> <rate>0.735</rate> </revenueAccessorialList> <revenueAccessorialList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/> <revenueAccessorialList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/> <stopOffRevenue>0.0</stopOffRevenue> <totalAccessorialRevenue>0.0</totalAccessorialRevenue> </totalRevenue> </rateQueryResponseList> </RateQueryResponses> </RateResponse>
当前使用的代码
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_XML); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_XML)); HttpEntity<QueryRequest> requestlEntity = new HttpEntity<>(rreq, headers); ResponseEntity<String> qrlEntity = null; return restTemplate.exchange(serviceEp, HttpMethod.POST, requestlEntity, String.class); // return restTemplate.postForEntity(serviceEp, requestlEntity, String.class);
解决办法
一、修复RestTemplate的问题
1. 自定义XML消息转换器
RestTemplate默认的MappingJackson2XmlHttpMessageConverter可能对重复元素和xsi:nil属性处理不当,可通过配置Jackson XML模块调整:
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter(); JacksonXmlModule module = new JacksonXmlModule(); // 关闭默认包装,适配重复元素 module.setDefaultUseWrapper(false); XmlMapper xmlMapper = new XmlMapper(module); // 忽略未知属性,避免解析报错 xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 允许接受空数组/元素,保留xsi:nil的项 xmlMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, false); converter.setObjectMapper(xmlMapper); // 替换原有的XML转换器 restTemplate.getMessageConverters().replaceAll(c -> c instanceof MappingJackson2XmlHttpMessageConverter ? converter : c ); return restTemplate; }
2. 直接读取原始响应流
如果只需要原始XML字符串,绕过消息转换器的自动处理,直接读取响应体的输入流:
ResponseEntity<Resource> response = restTemplate.exchange(serviceEp, HttpMethod.POST, requestlEntity, Resource.class); String rawXml = StreamUtils.copyToString(response.getBody().getInputStream(), StandardCharsets.UTF_8); // 后续处理rawXml即可
二、替代RestTemplate的方案
1. WebClient(Spring官方推荐)
Spring WebFlux提供的WebClient是异步非阻塞的HTTP客户端,处理XML更灵活:
// 配置WebClient @Bean public WebClient webClient() { return WebClient.builder() .codecs(configurer -> { // 使用JAXB编解码器处理XML configurer.defaultCodecs().jaxb2Encoder(new Jaxb2Encoder()); configurer.defaultCodecs().jaxb2Decoder(new Jaxb2Decoder()); }) .build(); } // 调用示例(同步方式) String xmlResponse = webClient.post() .uri(serviceEp) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML) .bodyValue(rreq) .retrieve() .bodyToMono(String.class) .block();
2. Apache HttpClient
直接使用原生HTTP客户端,完全控制请求和响应处理,避免Spring消息转换器的干扰:
// 需要先把QueryRequest序列化为XML字符串,这里假设已经有xmlRequestString CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(serviceEp); httpPost.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE); httpPost.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE); httpPost.setEntity(new StringEntity(xmlRequestString, StandardCharsets.UTF_8)); CloseableHttpResponse response = httpClient.execute(httpPost); String rawXml = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); // 关闭资源 response.close(); httpClient.close();
内容的提问来源于stack exchange,提问作者daoud175
相关产品推荐
相关产品推荐

