You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

验证要点

  1. 确认响应头的Content-Type确实是application/xml;charset=iso-8859-1
  2. 检查XML响应的声明部分,如果存在encoding="UTF-8",优先用方案1强制覆盖
  3. 确保项目中没有其他XML解析相关的配置干扰Jaxb2的行为

内容的提问来源于stack exchange,提问作者Preben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 10:24:57