• RestTemplate--解决中文乱码


    【原文链接】:https://blog.tecchen.xyz ,博文同步发布到博客园。
    由于精力有限,对文章的更新可能不能及时同步,请点击上面的原文链接访问最新内容。
    欢迎访问我的个人网站:https://www.tecchen.xyz

    在开发扇贝-每日一句时,使用RestTemplate请求扇贝接口,并保存返回的数据。原本正常的代码,经过架构升级后,请求接口时,会返回乱码数据。经过直接访问接口等形式,最终确认是RestTemplate这个bean有问题。
    对RestTemplate的声明也比较简单,通过对apache的httpclient进行封装,返回bean实例。代码如下:

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate(httpRequestFactory());
    }
    
    

    通过断点debug发现以String格式接收数据时,底层采用的是StringHttpMessageConverter来处理请求。查看RestTemplate的构造方法如下:

    public RestTemplate() {
        this.messageConverters = new ArrayList();
        this.errorHandler = new DefaultResponseErrorHandler();
        this.uriTemplateHandler = new DefaultUriBuilderFactory();
        this.headersExtractor = new RestTemplate.HeadersExtractor();
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter(false));
        this.messageConverters.add(new SourceHttpMessageConverter());
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
        if (romePresent) {
            this.messageConverters.add(new AtomFeedHttpMessageConverter());
            this.messageConverters.add(new RssChannelHttpMessageConverter());
        }
    
        if (jackson2XmlPresent) {
            this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
        } else if (jaxb2Present) {
            this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
        }
    
        if (jackson2Present) {
            this.messageConverters.add(new MappingJackson2HttpMessageConverter());
        } else if (gsonPresent) {
            this.messageConverters.add(new GsonHttpMessageConverter());
        } else if (jsonbPresent) {
            this.messageConverters.add(new JsonbHttpMessageConverter());
        }
    
        if (jackson2SmilePresent) {
            this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
        }
    
        if (jackson2CborPresent) {
            this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
        }
    }
    

    其中的StringHttpMessageConverter构造方法使用了默认字符集:ISO-8859-1。

    public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
        public static final Charset DEFAULT_CHARSET;
        ……
        public StringHttpMessageConverter() {
            this(DEFAULT_CHARSET);
        }
        ……
        static {
            DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
        }
    }
    

    private final List<HttpMessageConverter<?>> messageConverters
    根据RestTemplate的构造方法的源码得知所有的HttpMessageConverter都是放在final List<HttpMessageConverter<?>> messageConverters这个常量集合中。虽然集合不可修改,但是可以对其中的元素StringHttpMessageConverter进行修改。
    解决方案思路都是将ISO-8859-1的StringHttpMessageConverter替换为UTF-8的StringHttpMessageConverter。

    • 示例代码一
    restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    
    • 示例代码二
    for (HttpMessageConverter<?> httpMessageConverter : restTemplate.getMessageConverters()) {
        if (httpMessageConverter instanceof StringHttpMessageConverter) {
            ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName("UTF-8"));
        }
    }
    
    • 示例代码三
    // stream .findFirst(); 也是可以的
    Optional<HttpMessageConverter<?>> converter = restTemplate.getMessageConverters().stream().filter(c -> c instanceof StringHttpMessageConverter).findAny();
    if(converter.isPresent()) {
        ((StringHttpMessageConverter) converter.get()).setDefaultCharset(Charset.forName("UTF-8"));
    }
    
  • 相关阅读:
    Python函数式编程(一):高级函数
    Python高级特性:列表生成式
    Python高级特性:迭代
    Python高级特性:切片
    Python学习笔记
    关于相机拍照获取图片onActivityResult返回data 为null的问题
    191019
    状语和状语从句
    191018
    191017
  • 原文地址:https://www.cnblogs.com/Candies/p/10398584.html
Copyright © 2020-2023  润新知