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

使用spring,使用以下代码:

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

我明白了

 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] 

pojo的片段:

 @XmlRootElement(name="TheProductList") public class ProductList { @XmlElement(required = true, name = "date") private LocalDate importDate; 

从Spring的角度来看,使用HttpMessageConverter注册的HttpMessageConverter实例RestTemplate能将text/html内容转换为ProductList对象。 感兴趣的方法是HttpMessageConverter#canRead(Class, MediaType) 。 所有上述实现都返回false ,包括Jaxb2RootElementHttpMessageConverter

由于没有HttpMessageConverter可以读取您的HTTP响应,因此处理失败并出现exception。

如果您可以控制服务器响应,请对其进行修改以将Content-type设置为application/xmltext/xml或与application/*+xml匹配的内容。

如果你不控制服务器响应,你需要编写和注册你自己的HttpMessageConverter (可以扩展Spring类,参见AbstractXmlHttpMessageConverter及其子类),它们可以读取和转换text/html

如果无法更改服务器媒体类型响应,则可以扩展GsonHttpMessageConverter以处理其他支持类型

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

如果您使用的是Spring Boot,则可能需要确保在类路径中具有Jackson依赖项。 您可以通过以下方式手动完成:

   com.fasterxml.jackson.core jackson-annotations   com.fasterxml.jackson.core jackson-core   com.fasterxml.jackson.core jackson-databind  

或者您可以使用Web启动器:

  org.springframework.boot spring-boot-starter-web  

你可以组成一个RestTemplateXML类,它扩展了RestTemplate。 然后重写doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor) ,并显式获取response-headers并将content-type设置为application/xml

现在Spring读取头文件并知道它是`application / xml’。 这是一种黑客但它的工作原理。

 public class RestTemplateXML extends RestTemplate { @Override protected  T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor 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); } } 

尝试这个:

  com.fasterxml.jackson.core jackson-databind 2.6.0  

除了所有的答案,如果你碰巧收到text/html而你期望别的东西(即application/json ),它可能表明服务器端(比如404)和错误页面发生错误返回而不是您的数据。

所以它发生在我的情况下。 希望它能节省一些人的时间。

或者你可以使用

public void setSupportedMediaTypes(List supportedMediaTypes)

方法属于AbstractHttpMessageConverter ,添加一些你喜欢的ContentTypes 。 这种方式可以让MappingJackson2HttpMessageConverter canRead()你的响应,并将它转换为你想要的类,在这种情况下,它是ProductList类。

我认为这一步应该与Spring Context初始化相关联。 例如,通过使用

实现ApplicationListener {…}

Vadim Zin4uk的答案的改进只是使用现有的GsonHttpMessageConverter类,但是调用setSupportedMediaTypes()setter。

对于Spring启动应用程序,这会导致向配置类添加以下内容:

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

这并没有回答这个问题,但是如果有人遇到这个问题时遇到了这个没有找到合适的消息转换器的例外,这就是我的问题和解决方案。

在Spring 4.0.9中,我们能够发送它

  JSONObject jsonCredential = new JSONObject(); jsonCredential.put(APPLICATION_CREDENTIALS, data); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); ResponseEntity res = restTemplate.exchange(myRestUrl), HttpMethod.POST,request, String.class); 

在Spring 4.3.5版本中,我们开始看到错误消息,找不到转换器。 COnverets工作的方式是,如果你在类路径中有它,它们会被注册.jackson-asl仍然在类路径中但是没有被spring识别。 我们用更快的xml jackson核心取代Jackson-asl。 一旦我们添加,我可以看到转换器正在注册 在此处输入图像描述