json RestClientException: 无法提取响应。没有找到合适的 HttpMessageConverter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44176335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:53:44  来源:igfitidea点击:

RestClientException: Could not extract response. no suitable HttpMessageConverter found

jsonspringrestspring-mvcresttemplate

提问by Nu?ito de la Calzada

Using the curl command:

使用 curl 命令:

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

I am getting a JSON response:

我收到一个 JSON 响应:

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

I save the response on a txt file and parse it using Hymanson, and everything is fine

我将响应保存在一个 txt 文件中并使用 Hymanson 解析它,一切都很好

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

and I assume I should get the same result using RestTemplate but that's not the case

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

RestTemplate restTemplate = new RestTemplate();
        MessageList messageList = 
                restTemplate.getForObject("http://592693f43c87815f9b8145e9:[email protected]/api/devicetypes/591570373c87894b4eece34d/messages", MessageList.class);

I got an error instead

我得到了一个错误

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)

I tried to set the contentType:

我试图设置内容类型:

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

but then I got a compilation error

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

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

I also tried to add a the Hymanson Message converter

我还尝试添加 Hymanson Message 转换器

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

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

But then I got this error:

但是后来我收到了这个错误:

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)

I also tried adding the class

我也尝试添加类

@Configuration
@EnableWebMvc
public class MvcConf extends WebMvcConfigurationSupport {

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

    @Bean
    MappingHymanson2HttpMessageConverter converter() {

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

}

but I got the error:

但我得到了错误:

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)

回答by Ilya Dyoshin

The main problem here is content type [text/html;charset=iso-8859-1]received from the service, however the real content type should be application/json;charset=iso-8859-1

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

In order to overcome this you can introduce custom message converter. and register it for all kind of responses (i.e. ignore the response content type header). Just like this

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

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

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

回答by Alex R

While the accepted answer solved the OP's original problem, I suspect most people finding this question through a Google search are likely (statistically speaking) to be having an entirely different problem which just happens to throw the same no suitable HttpMessageConverter foundexception.

虽然接受的答案解决了 OP 的原始问题,但我怀疑大多数通过谷歌搜索找到这个问题的人(从统计上讲)可能会遇到一个完全不同的问题,恰好抛出相同的没有合适的 HttpMessageConverter found异常。

What happens under the covers is that MappingHymanson2HttpMessageConverterswallows any exceptions that occur in its canRead()method, which is supposed to auto-detect whether the payload is suitable for json decoding. The exception is replaced by a simple boolean return that basically communicates sorry, I don't know how to decode this messageto the higher level APIs (RestClient). Only after all other converters' canRead() methods return false, the no suitable HttpMessageConverter foundexception is thrown by the higher-level API, totally obscuring the true problem.

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

For people who have not found the root cause (like you and me, but not the OP), the way to troubleshoot this problem is to place a debugger breakpoint on onMappingHymanson2HttpMessageConverter.canRead(), then enable a general breakpoint on any exception, and hit Continue. The next exception is the true root cause.

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

My specific error happened to be that one of the beans referenced an interface that was missing the proper deserialization annotations.

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

回答by gbonehead

I was having a very similar problem, and it turned out to be quite simple; my client wasn't including a Hymanson dependency, even though the code all compiledcorrectly, the auto-magic converters for JSON weren't being included. See this RestTemplate-related solution.

我遇到了一个非常相似的问题,结果很简单;我的客户不包含 Hymanson 依赖项,即使代码都正确编译,但不包含 JSON 的自动魔术转换器。请参阅此 RestTemplate 相关解决方案。

In short, I added a Hymanson dependency to my pom.xml and it just worked:

简而言之,我在我的 pom.xml 中添加了一个 Hymanson 依赖项,它就起作用了:

<dependency>
    <groupId>com.fasterxml.Hymanson.core</groupId>
    <artifactId>Hymanson-databind</artifactId>
    <version>2.5.1</version>
</dependency>

回答by hirosht

If the above response by @Ilya Dyoshindidn't still retrieve, try to get the response into a String Object.

如果@Ilya Dyoshin的上述响应仍未检索到,请尝试将响应放入字符串对象中。

(For my self thought the error got solved by the code snippet by Ilya, the response retrieved was a failure(error) from the server.)

(我自己认为 Ilya 的代码片段解决了错误,检索到的响应是来自服务器的失败(错误)。)

HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
ResponseEntity<String> st = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); 

And Cast to the ResponseObject DTO (Json)

并转换为 ResponseObject DTO (Json)

Gson g = new Gson();
DTO dto = g.fromJson(st.getBody(), DTO.class); 

回答by Cyclotron3x3

Here is the approach I follow whenever I see this type of error:

这是我每次看到此类错误时遵循的方法:

  1. One way to debug this issue is by first taking whatever response is coming as String.class then applying Gson().fromJson(StringResp.body(), MyDTO.class). It will still fail most probably but this time it will throw the fields which are creating this error to happen in first place. Post the modification, we can use the previous approach as usual.
  1. 调试此问题的一种方法是首先将任何响应作为 String.class,然后应用 Gson().fromJson(StringResp.body(), MyDTO.class)。它仍然很可能会失败,但这次它会首先抛出创建此错误的字段。修改后,我们可以照常使用之前的方法。

ResponseEntity<String> respStr = restTemplate.exchange(URL,HttpMethod.GET, entity, String.class);
Gson g = new Gson();

ResponseEntity<String> respStr = restTemplate.exchange(URL,HttpMethod.GET, entity, String.class);
Gson g = new Gson();

The below step will throw error with the fields which is causing the issue

以下步骤将在导致问题的字段中引发错误

MyDTO resp = g.fromJson(respStr.getBody(), MyDTO.class);

I don't have the error message with me but it will point to the field which is problematic and the reason for it. Resolve those and try again with previous approach.

我没有错误消息,但它会指向有问题的字段及其原因。解决这些问题,然后用以前的方法重试。

回答by JN Gerbaux

In my case @Ilya Dyoshin's solution didn't work: The mediatype "*" was not allowed. I fix this error by adding a new converter to the restTemplate this way during initialization of the MockRestServiceServer:

就我而言,@Ilya Dyoshin 的解决方案不起作用:不允许使用媒体类型“*”。我通过在 MockRestServiceServer 初始化期间以这种方式向 restTemplate 添加一个新转换器来修复此错误:

  MappingHymanson2HttpMessageConverter mappingHymanson2HttpMessageConverter = 
                      new MappingHymanson2HttpMessageConverter();
  mappingHymanson2HttpMessageConverter.setSupportedMediaTypes(
                                    Arrays.asList(
                                       MediaType.APPLICATION_JSON, 
                                       MediaType.APPLICATION_OCTET_STREAM));
  restTemplate.getMessageConverters().add(mappingHymanson2HttpMessageConverter);
  mockServer = MockRestServiceServer.createServer(restTemplate);

(Based on the solution proposed by Yashwant Chavan on the blog named technicalkeeda)

(基于Yashwant Chavan在名为technicalkeeda的博客上提出的解决方案)

JN Gerbaux

杰博

回答by ikolomiyets

In my case it was caused by the absence of the Hymanson-core, Hymanson-annotations and Hymanson-databind jars from the runtime classpath. It did not complain with the usual ClassNothFoundException as one would expect but rather with the error mentioned in the original question.

在我的情况下,它是由于运行时类路径中缺少 Hymanson-core、Hymanson-annotations 和 Hymanson-databind jar 造成的。它没有像人们期望的那样抱怨通常的 ClassNothFoundException,而是抱怨原始问题中提到的错误。

回答by Naimish Dixit

You need to create your own converter and implement it before making a GET request.

您需要创建自己的转换器并在发出 GET 请求之前实施它。

RestTemplate  restTemplate = new RestTemplate();

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

MappingHymanson2HttpMessageConverter converter = new MappingHymanson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));         
messageConverters.add(converter);  
restTemplate.setMessageConverters(messageConverters);    

回答by Romain COMTET

Other possible solution : I tried to map the result of a restTemplate.getForObject with a private class instance (defined inside of my working class). It did not work, but if I define the object to public, inside its own file, it worked correctly.

其他可能的解决方案:我尝试将 restTemplate.getForObject 的结果映射到私有类实例(在我的工作类中定义)。它不起作用,但如果我将对象定义为 public,在它自己的文件中,它可以正常工作。

回答by Abhay Maniyar

Spring sets the default content-type to octet-streamwhen the response is missing that field. All you need to do is to add a message converter to fix this.

Spring 将默认内容类型设置octet-stream为响应缺少该字段时。您需要做的就是添加一个消息转换器来解决这个问题。