简体   繁体   English

没有找到适合响应类型的 HttpMessageConverter

[英]no suitable HttpMessageConverter found for response type

Using spring, with this code:使用 spring,使用以下代码:

List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for(HttpMessageConverter httpMessageConverter : messageConverters){
  System.out.println(httpMessageConverter);
}
ResponseEntity<ProductList> productList = restTemplate.getForEntity(productDataUrl,ProductList.class);

I get我明白了

org.springframework.http.converter.ByteArrayHttpMessageConverter@34649ee4
org.springframework.http.converter.StringHttpMessageConverter@39fba59b
org.springframework.http.converter.ResourceHttpMessageConverter@383580da
org.springframework.http.converter.xml.SourceHttpMessageConverter@409e850a
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@673074aa
org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter@1e3b79d3
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@52bb1b26

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.mycopmany.ProductList] and content type [text/html;charset=UTF-8]

The a snippet of the pojo: pojo的片段:

@XmlRootElement(name="TheProductList")
public class ProductList {

@XmlElement(required = true, name = "date")
private LocalDate importDate;

From a Spring point of view, none of the HttpMessageConverter instances registered with the RestTemplate can convert text/html content to a ProductList object.从 Spring 的角度来看,注册到RestTemplateHttpMessageConverter实例RestTemplate能将text/html内容转换为ProductList对象。 The method of interest is HttpMessageConverter#canRead(Class, MediaType) .感兴趣的方法是HttpMessageConverter#canRead(Class, MediaType) The implementation for all of the above returns false , including Jaxb2RootElementHttpMessageConverter .以上所有的实现都返回false ,包括Jaxb2RootElementHttpMessageConverter

Since no HttpMessageConverter can read your HTTP response, processing fails with an exception.由于没有HttpMessageConverter可以读取您的 HTTP 响应,因此处理失败并出现异常。

If you can control the server response, modify it to set the Content-type to application/xml , text/xml , or something matching application/*+xml .如果您可以控制服务器响应,请修改它以将Content-type设置为application/xmltext/xml或匹配application/*+xml

If you don't control the server response, you'll need to write and register your own HttpMessageConverter (which can extend the Spring classes, see AbstractXmlHttpMessageConverter and its sub classes) that can read and convert text/html .如果您不控制服务器响应,则需要编写和注册您自己的HttpMessageConverter (它可以扩展 Spring 类,请参阅AbstractXmlHttpMessageConverter及其子类),它可以读取和转换text/html

You could also simply tell your RestTemplate to accept all media types:您也可以简单地告诉您的RestTemplate接受所有媒体类型:

@Bean
public RestTemplate restTemplate() {
   final RestTemplate restTemplate = new RestTemplate();

   List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
   MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
   converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
   messageConverters.add(converter);
   restTemplate.setMessageConverters(messageConverters);

   return restTemplate;
}

If you are using Spring Boot, you might want to make sure you have the Jackson dependency in your classpath.如果您使用的是 Spring Boot,您可能需要确保您的类路径中有 Jackson 依赖项。 You can do this manually via:您可以通过以下方式手动执行此操作:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>

Or you can use the web starter:或者您可以使用网络启动器:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

If you can't change server media-type response, you can extend GsonHttpMessageConverter to process additional support types如果您无法更改服务器媒体类型响应,则可以扩展 GsonHttpMessageConverter 以处理其他支持类型

public class MyGsonHttpMessageConverter extends GsonHttpMessageConverter {
    public MyGsonHttpMessageConverter() {
        List<MediaType> types = Arrays.asList(
                new MediaType("text", "html", DEFAULT_CHARSET),
                new MediaType("application", "json", DEFAULT_CHARSET),
                new MediaType("application", "*+json", DEFAULT_CHARSET)
        );
        super.setSupportedMediaTypes(types);
    }
}

In addition to all the answers, if you happen to receive in response text/html while you've expected something else (ie application/json ), it may suggest that an error occurred on the server side (say 404) and the error page was returned instead of your data.除了所有答案之外,如果您碰巧在响应text/html收到其他内容(即application/json ),则可能表明服务器端发生了错误(例如 404)和错误页面被返回而不是您的数据。

So it happened in my case.所以它发生在我的情况下。 Hope it will save somebody's time.希望它会节省某人的时间。

You can make up a class, RestTemplateXML, which extends RestTemplate.你可以组成一个类,RestTemplateXML,它扩展了RestTemplate。 Then override doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor<T>) , and explicitly get response-headers and set content-type to application/xml .然后覆盖doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor<T>) ,并显式获取response-headers并将content-type设置为application/xml

Now Spring reads the headers and knows that it is `application/xml'.现在 Spring 读取标头并知道它是“application/xml”。 It is kind of a hack but it works.这是一种黑客,但它的工作原理。

public class RestTemplateXML extends RestTemplate {

  @Override
  protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
        ResponseExtractor<T> responseExtractor) throws RestClientException {

     logger.info( RestTemplateXML.class.getSuperclass().getSimpleName() + ".doExecute() is overridden");

     Assert.notNull(url, "'url' must not be null");
     Assert.notNull(method, "'method' must not be null");
     ClientHttpResponse response = null;
     try {
        ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
           requestCallback.doWithRequest(request);
        }
        response = request.execute();

        // Set ContentType to XML
        response.getHeaders().setContentType(MediaType.APPLICATION_XML);

        if (!getErrorHandler().hasError(response)) {
           logResponseStatus(method, url, response);
        }
        else {
           handleResponseError(method, url, response);
        }
        if (responseExtractor != null) {
           return responseExtractor.extractData(response);
        }
        else {
           return null;
        }
     }
     catch (IOException ex) {
        throw new ResourceAccessException("I/O error on " + method.name() +
              " request for \"" + url + "\":" + ex.getMessage(), ex);
     }
     finally {
        if (response != null) {
           response.close();
        }
     }

  }

  private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) {
     if (logger.isDebugEnabled()) {
        try {
           logger.debug(method.name() + " request for \"" + url + "\" resulted in " +
                 response.getRawStatusCode() + " (" + response.getStatusText() + ")");
        }
        catch (IOException e) {
           // ignore
        }
     }
  }

  private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException {
     if (logger.isWarnEnabled()) {
        try {
           logger.warn(method.name() + " request for \"" + url + "\" resulted in " +
                 response.getRawStatusCode() + " (" + response.getStatusText() + "); invoking error handler");
        }
        catch (IOException e) {
           // ignore
        }
     }
     getErrorHandler().handleError(response);
  }
}

Try this:尝试这个:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.1</version>
</dependency>

Or you can use或者你可以使用

public void setSupportedMediaTypes(List supportedMediaTypes) public void setSupportedMediaTypes(List supportedMediaTypes)

method which belongs to AbstractHttpMessageConverter<T> , to add some ContentTypes you like.属于AbstractHttpMessageConverter<T> ,添加一些您喜欢的ContentTypes This way can let the MappingJackson2HttpMessageConverter canRead() your response, and transform it to your desired Class, which on this case,is ProductList Class.这种方式可以让MappingJackson2HttpMessageConverter canRead()您的响应,并将其转换为您想要的类,在这种情况下,是 ProductList 类。

and I think this step should hooked up with the Spring Context initializing.我认为这一步应该与 Spring Context 初始化相关联。 for example, by using例如,通过使用

implements ApplicationListener { ... }实现 ApplicationListener { ... }

This is not answering the problem but if anyone comes to this question when they stumble upon this exception of no suitable message converter found, here is my problem and solution.这不是在回答问题,但是如果有人在偶然发现找不到合适的消息转换器的异常时遇到这个问题,这是我的问题和解决方案。

In Spring 4.0.9, we were able to send this在 Spring 4.0.9 中,我们能够发送这个

    JSONObject jsonCredential = new JSONObject();
    jsonCredential.put(APPLICATION_CREDENTIALS, data);

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

ResponseEntity<String> res = restTemplate.exchange(myRestUrl), HttpMethod.POST,request, String.class);

In Spring 4.3.5 release, we starting seeing errors with the message that converter was not found.在 Spring 4.3.5 版本中,我们开始看到带有找不到转换器的消息的错误。

The way Convertors work is that if you have it in your classpath, they get registered.转换器的工作方式是,如果您的类路径中有它,它们就会被注册。

Jackson-asl was still in classpath but was not being recognized by spring. Jackson-asl 仍然在 classpath 中,但没有被 spring 识别。 We replaced Jackson-asl with faster-xml jackson core.我们用 fast-xml jackson core 替换了 Jackson-asl。

Once we added I could see the converter being registered.添加后,我可以看到转换器正在注册。

在此处输入图片说明

A refinement of Vadim Zin4uk's answer is just to use the existing GsonHttpMessageConverter class but invoke the setSupportedMediaTypes() setter. Vadim Zin4uk 的答案的改进只是使用现有的 GsonHttpMessageConverter 类,但调用 setSupportedMediaTypes() 设置器。

For spring boot apps, this results into adding to following to your configuration classes:对于 Spring Boot 应用程序,这会导致将以下内容添加到您的配置类中:

@Bean
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
    GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
    converter.setGson(gson);
    List<MediaType> supportedMediaTypes = converter.getSupportedMediaTypes();
    if (! supportedMediaTypes.contains(TEXT_PLAIN)) {
        supportedMediaTypes = new ArrayList<>(supportedMediaTypes);
        supportedMediaTypes.add(TEXT_PLAIN);
        converter.setSupportedMediaTypes(supportedMediaTypes);
    }
    return converter;
}

I also had the same error message : "Could not extract response: no suitable HttpMessageConverter found for response type ..."我也有同样的错误消息:“无法提取响应:没有找到适合响应类型的 HttpMessageConverter ......”

This occured when I was trying to get info from a link that did not return the object type I wanted to convert or when the link did not return anything.当我试图从没有返回我想要转换的对象类型的链接中获取信息时,或者当链接没有返回任何内容时,就会发生这种情况。 I handled it using a try catch block :我使用 try catch 块处理它:

 try {
        status = restTemplate
            .getForObject(statusResourceUrl, Status.class);

        //TODO add new exceptions if necessary or simply use Exception
    } catch (BeanCreationException | UnknownContentTypeException | HttpClientErrorException e) {
        status.setStatus("DOWN");
        System.out.println("exception " + e.getMessage());
    }

I was also facing the same issue in last week.上周我也面临同样的问题。 Tried the above solution which marked as accepted but didnt worked.尝试了上述标记为已接受但无效的解决方案。

When this will come : While calling the external URL(REST call) and the response is the complex object.何时到来:调用外部 URL(REST 调用)时,响应是复杂的 object。

What was wrong : was adding unnecessary the converter using the below code出了什么问题:使用以下代码添加了不必要的转换器

org.springframework.web.client.restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));

Solution : Just add the below dependency解决方案:只需添加以下依赖项

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

Because spring boot add all the default message converters.因为 spring 引导添加所有默认消息转换器。 No need to add any extra.无需添加任何额外内容。 Not even any JaxB dependency.甚至没有任何 JaxB 依赖项。 If present please delete and Try it will work如果存在,请删除并尝试它会工作

Danke!!丹克!!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 找不到适合响应类型和内容类型的HttpMessageConverter - no suitable HttpMessageConverter found for response type and content type 没有为响应类型找到合适的HttpMessageConverter - Custom RestTemplate - No suitable HttpMessageConverter found for response type - Custom RestTemplate Android版Spring-无法提取响应:找不到适合响应类型的HttpMessageConverter - Spring for Android - Could not extract response: no suitable HttpMessageConverter found for response type RestClientException无法提取响应:找不到合适的HttpMessageConverter作为响应类型 - RestClientException Could not extract response: no suitable HttpMessageConverter found for response type 找不到适用于响应类型[..]和内容类型[application / json]的HttpMessageConverter - No suitable HttpMessageConverter found for response type [..] and content type [application/json] 转换JSON响应时找不到合适的HttpMessageConverter? - No suitable HttpMessageConverter found when converting JSON response? 无法提取响应:找不到合适的HttpMessageConverter - Could not extract response: no suitable HttpMessageConverter found 无法提取响应:没有找到适合响应类型 class 和内容类型 [text/html] 的 HttpMessageConverter - Could not extract response: no suitable HttpMessageConverter found for response type class and content type [text/html] Spring Rest客户端实现:无法提取响应:没有为xstreamMarshaller找到适合的响应类型的HttpMessageConverter - Spring Rest Client implementation : Could not extract response: no suitable HttpMessageConverter found for response type with xstreamMarshaller 契约:未找到响应类型的HttpMessageConverter - Pact: no HttpMessageConverter found for response type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM