RestClientException:无法提取响应。找不到合适的 HttpMessageConverter

新手上路,请多包涵

使用卷曲命令:

 curl -u 591bf65f50057469f10b5fd9:0cf17f9b03d056ds0e11e48497e506a2 https://backend.tdk.com/api/devicetypes/59147fd79e93s12e61499ffe/messages

我收到一个 JSON 响应:

 {"data":[{"device":"18SE62","time":1494516023,"data":"3235","snr":"36.72",...

我将响应保存在 txt 文件中并使用 jackson 对其进行解析,一切都很好

ObjectMapper mapper = new ObjectMapper();
        File f = new File(getClass().getResource
                    ("/result.json").getFile());
        MessageList messageList = mapper.readValue(f, MessageList.class);

我假设我应该使用 RestTemplate 得到相同的结果,但事实并非如此

RestTemplate restTemplate = new RestTemplate();
        MessageList messageList =
                restTemplate.getForObject("http://592693f43c87815f9b8145e9:f099c85d84d4e325a2186c02bd0caeef@backend.tdk.com/api/devicetypes/591570373c87894b4eece34d/messages", MessageList.class);

我得到了一个错误

Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.tdk.domain.backend.MessageList] and content type [text/html;charset=iso-8859-1]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:287)
    at com.tdk.controllers.restful.client.RestTemplateExample.main(RestTemplateExample.java:27)

我试图设置内容类型:

 HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

        MessageList messageList =
                restTemplate.getForObject(url, entity, MessageList.class);

但后来我得到了一个编译错误

The method getForObject(String, Class<T>, Object...) in the type RestTemplate is not applicable for the arguments (String, HttpEntity<String>,
 Class<MessageList>)

我还尝试添加一个 Jackson Message 转换器

  List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
            //Add the Jackson Message converter
            messageConverters.add(new MappingJackson2HttpMessageConverter());
            //Add the message converters to the restTemplate
            restTemplate.setMessageConverters(messageConverters);

            MessageList messageList =
                    restTemplate.getForObject(url, MessageList.class);

但后来我得到了这个错误:

 Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.tdk.domain.backend.MessageList] and content type [text/html;charset=iso-8859-1]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:287)
    at com.tdk.controllers.restful.client.RestTemplateExample.main(RestTemplateExample.java:51)

我也尝试添加课程

@Configuration
@EnableWebMvc
public class MvcConf extends WebMvcConfigurationSupport {

    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(converter());
        addDefaultHttpMessageConverters(converters);
    }

    @Bean
    MappingJackson2HttpMessageConverter converter() {

        MappingJackson2HttpMessageConverter converter
                    = new MappingJackson2HttpMessageConverter();
        return converter;
    }

}

但我得到了错误:

 org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.tdk.domain.backend.MessageList] and content type [text/html;charset=iso-8859-1]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:287)

原文由 Nunyet de Can Calçada 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

这里的主要问题是从服务接收到的 内容类型 [text/html;charset=iso-8859-1] ,但是真正的内容类型应该是 application/json;charset=iso-8859-1

为了克服这个问题,您可以引入自定义消息转换器。并为所有类型的响应注册它(即忽略响应内容类型标头)。像这样

List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
//Add the Jackson Message converter
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

// Note: here we are making this converter to process any kind of response,
// not only application/*json, which is the default behaviour
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
messageConverters.add(converter);
restTemplate.setMessageConverters(messageConverters);

原文由 Ilya Dyoshin 发布,翻译遵循 CC BY-SA 4.0 许可协议

虽然接受的答案解决了 OP 的原始问题,但大多数通过谷歌搜索找到这个问题的人可能遇到了一个完全不同的问题,恰好抛出相同的 no suitable HttpMessageConverter found 异常。

幕后发生的事情是 MappingJackson2HttpMessageConverter 吞下了其 canRead() 方法中发生的任何异常,该方法应该自动检测有效负载是否适合 json 解码。异常被一个简单的布尔返回值所取代,该返回值基本上表示 抱歉,我不知道如何将此消息解码 为更高级别的 API ( RestClient )。只有在所有其他转换器的 canRead() 方法返回 false 之后,更高级别的 API 才会抛出 no suitable HttpMessageConverter found 异常,完全掩盖了真正的问题。

对于没有找到根本原因的人(比如你和我,但不是 OP),解决这个问题的方法是在 onMappingJackson2HttpMessageConverter.canRead() 上放置一个调试器断点,然后在任何异常上启用一个通用断点,然后点击继续。下一个异常是真正的根本原因。

我的具体错误恰好是其中一个 bean 引用了一个缺少正确的反序列化注释的接口。

未来的更新

在我的许多项目中,这已被证明是一个反复出现的问题,因此我开发了一个更主动的解决方案。每当我需要专门处理 JSON(无 XML 或其他格式)时,我现在用以下实例替换我的 RestTemplate bean:

 public class JsonRestTemplate extends RestTemplate {

    public JsonRestTemplate(
            ClientHttpRequestFactory clientHttpRequestFactory) {
        super(clientHttpRequestFactory);

        // Force a sensible JSON mapper.
        // Customize as needed for your project's definition of "sensible":
        ObjectMapper objectMapper = new ObjectMapper()
                .registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule())
                .configure(
                        SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter() {

            public boolean canRead(java.lang.Class<?> clazz,
                    org.springframework.http.MediaType mediaType) {
                return true;
            }
            public boolean canRead(java.lang.reflect.Type type,
                    java.lang.Class<?> contextClass,
                    org.springframework.http.MediaType mediaType) {
                return true;
            }
            protected boolean canRead(
                    org.springframework.http.MediaType mediaType) {
                return true;
            }
        };

        jsonMessageConverter.setObjectMapper(objectMapper);
        messageConverters.add(jsonMessageConverter);
        super.setMessageConverters(messageConverters);

    }
}

此自定义使 RestClient 无法理解 JSON 以外的任何内容。好处是可能出现的任何错误消息都将更明确地说明问题所在。

原文由 Alex R 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题