Spring Boot RestClient无法解析ISO-8859-1编码XML响应求助
解决Spring Boot 3.4.4中ISO-8859-1编码XML响应解析错误
问题原因分析
你遇到的Invalid byte 1 of 1-byte UTF-8 sequence错误,本质是JAXB解析时使用UTF-8编码读取ISO-8859-1字节流导致的编码不匹配。常见触发场景:
- XML响应的
<?xml>声明中指定了encoding="UTF-8",JAXB会优先遵循该声明,忽略响应头的charset=iso-8859-1 - 消息转换器顺序问题,其他XML转换器(如Jackson XML转换器)先于Jaxb2转换器处理响应,未正确设置编码
- Jaxb2RootElementHttpMessageConverter仅设置了默认字符集,但未强制Unmarshaller使用该编码
解决方案
方案1:强制JAXB Unmarshaller使用指定编码
修改RestClient配置,不仅设置转换器的默认字符集,还通过Unmarshaller自定义器强制编码:
@Bean(name = "woRestClient") RestClient woRestClient(RestClient.Builder builder) { var factory = new JdkClientHttpRequestFactory(createHttpClient()); return builder .baseUrl(configuration.endpointUrl) .messageConverters(httpMessageConverters -> { httpMessageConverters.forEach(httpMessageConverter -> { if (httpMessageConverter instanceof Jaxb2RootElementHttpMessageConverter converter) { // 设置默认字符集 converter.setDefaultCharset(StandardCharsets.ISO_8859_1); // 强制Unmarshaller使用ISO-8859-1编码,忽略XML声明的编码 converter.setUnmarshallerCustomizer(unmarshaller -> { unmarshaller.setProperty("jaxb.encoding", StandardCharsets.ISO_8859_1.name()); // 针对Xerces解析器的额外配置(可选) unmarshaller.setProperty("http://apache.org/xml/properties/input-encoding", StandardCharsets.ISO_8859_1.name()); }); } }); }) .requestFactory(factory) .build(); } private HttpClient createHttpClient() { return HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1) .connectTimeout(Duration.ofSeconds(5)) .build(); }
方案2:调整消息转换器顺序,确保Jaxb2优先处理
如果存在其他XML消息转换器(如MappingJackson2XmlHttpMessageConverter),它们可能先于Jaxb2转换器处理响应,导致编码设置失效。可以移除这些转换器或调整顺序:
@Bean(name = "woRestClient") RestClient woRestClient(RestClient.Builder builder) { var factory = new JdkClientHttpRequestFactory(createHttpClient()); return builder .baseUrl(configuration.endpointUrl) .messageConverters(httpMessageConverters -> { // 移除Jackson XML转换器(如果存在) httpMessageConverters.removeIf(converter -> converter instanceof MappingJackson2XmlHttpMessageConverter); // 创建并配置自定义Jaxb2转换器 Jaxb2RootElementHttpMessageConverter jaxbConverter = new Jaxb2RootElementHttpMessageConverter(); jaxbConverter.setDefaultCharset(StandardCharsets.ISO_8859_1); jaxbConverter.setUnmarshallerCustomizer(unmarshaller -> { unmarshaller.setProperty("jaxb.encoding", StandardCharsets.ISO_8859_1.name()); }); // 将Jaxb2转换器添加到最前面,确保优先处理XML响应 httpMessageConverters.add(0, jaxbConverter); }) .requestFactory(factory) .build(); }
方案3:手动读取响应体并解析(兜底方案)
如果上述方案无效,可以绕过自动消息转换,手动按ISO-8859-1读取响应体后再解析:
// 调用服务并手动读取响应 RestClient restClient = applicationContext.getBean("woRestClient", RestClient.class); InputStream responseStream = restClient.get() .uri("/your-service-endpoint") .retrieve() .body(InputStream.class); // 按ISO-8859-1编码转换为字符串 String xmlContent = new String(responseStream.readAllBytes(), StandardCharsets.ISO_8859_1); // 用JAXB手动解析 JAXBContext jaxbContext = JAXBContext.newInstance(Programs.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); Programs programs = (Programs) unmarshaller.unmarshal(new StringReader(xmlContent));
验证要点
- 确认响应头的
Content-Type确实是application/xml;charset=iso-8859-1 - 检查XML响应的声明部分,如果存在
encoding="UTF-8",优先用方案1强制覆盖 - 确保项目中没有其他XML解析相关的配置干扰Jaxb2的行为
内容的提问来源于stack exchange,提问作者Preben
相关产品推荐
相关产品推荐

