解決 RestTemplate 報錯 UnknownContentTypeException


之前項目都是使用 HttpClient 進行 api 調用,代碼較為復雜。新項目正好想試試 spring 自家封裝的 RestTemplate,沒想到第一個小程序服務端獲取 openid 的請求直接就翻車了,異常如下:

org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class ***] and content type [text/plain]

debug 發現響應內容正常,出錯的原因是微信這個坑貨 響應頭中的 Content-Type 是 text/plain。

解決方法有兩種,如下:

使用 String 類型接收

String res = restTemplate.getForObject(url,String.class,map);
// 使用json轉換工具將String類型的數據轉換為對象

這個方法簡單有效,但是每個 api 調用的地方都這么寫下感覺挺丑的

自定義 HttpMessageConverter

研究源碼發現 RestTemplate 在靜態代碼塊和無參構造中通過類加載器判斷,初始化對應的消息轉換器

// RestTemplate部分源碼
public RestTemplate() {
    this.messageConverters.add(new ByteArrayHttpMessageConverter());
    this.messageConverters.add(new StringHttpMessageConverter());
    this.messageConverters.add(new ResourceHttpMessageConverter(false));
    if (jackson2Present) {
        this.messageConverters.add(new MappingJackson2HttpMessageConverter());
    }
    else if (gsonPresent) {
        this.messageConverters.add(new GsonHttpMessageConverter());
    }
    else if (jsonbPresent) {
        this.messageConverters.add(new JsonbHttpMessageConverter());
    }
    //...
}

我的項目中使用 jackson 作為 json 序列化工具,所以直接繼承 MappingJackson2HttpMessageConverter 這個實現就好了。如果你使用其他的 json 序列化工具,就根據源碼自行修改

// CustomJacksonHttpMessageConverter.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.util.Collections;

public class CustomJacksonHttpMessageConverter extends MappingJackson2HttpMessageConverter {
    public CustomJacksonHttpMessageConverter() {
        this(Jackson2ObjectMapperBuilder.json().build());
    }

    public CustomJacksonHttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper);
        // 這里是重點,增加支持的類型,看你的情況加
        // 我這里目前只需要加個 TEXT/PLAIN
        setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN,
                MediaType.APPLICATION_JSON,
                new MediaType("application", "*+json")));
    }
}

最后修改下 RestTemplate 的配置,將自定義的消息轉換器和原來的替換

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;


@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        // 創建 RestTemplate 實例, 我這里使用的OkHttp
        RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
        // 替換默認的 Jackson 消息轉換器實現
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
        while (iterator.hasNext()) {
            HttpMessageConverter<?> next = iterator.next();
            if (next instanceof MappingJackson2HttpMessageConverter) {
                iterator.remove();
                break;
            }
        }
        messageConverters.add(new CustomJacksonHttpMessageConverter());
        return restTemplate;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM