RestTemplate--解決中文亂碼

【原文連接】:https://blog.tecchen.xyz ,博文同步發佈到博客園。
因爲精力有限,對文章的更新可能不能及時同步,請點擊上面的原文連接訪問最新內容。
歡迎訪問個人我的網站:https://www.tecchen.xyzhtml

在開發扇貝-每日一句時,使用RestTemplate請求扇貝接口,並保存返回的數據。本來正常的代碼,通過架構升級後,請求接口時,會返回亂碼數據。通過直接訪問接口等形式,最終確認是RestTemplate這個bean有問題。
對RestTemplate的聲明也比較簡單,經過對apache的httpclient進行封裝,返回bean實例。代碼以下:java

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

經過斷點debug發現以String格式接收數據時,底層採用的是StringHttpMessageConverter來處理請求。查看RestTemplate的構造方法以下:apache

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。json

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。api

  • 示例代碼一
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"));
}
相關文章
相關標籤/搜索