springboot: no suitable HttpMessageConverter found for response


最近在使用springboot调用第三方接口的时候,出现了这个异常Could not extract response: no suitable HttpMessageConverter found for response type [cn.justme.sboot.entity.BaseResp<java.lang.String>] and content type [text/plain;charset=UTF-8],这里就来分析一下具体问题

事件还原

1. pom.xml

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

2. feign调用

@FeignClient(name = "test", url = "http://localhost:8080")
public interface TestClient {
    @GetMapping("/api/test")
    BaseResp<String> test();
}

三方接口返回的是json,这里我是使用feign调用。

3. 第三方接口

接口: /api/test

{
    "status": 0,
    "message": "",
    "data": null
}


我们可以看到Content-Type: text/plain;charset=UTF-8,

原因分析

springboot默认的处理json的HttpMessageConverterMappingJackson2HttpMessageConverter

public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
    super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}

但是MappingJackson2HttpMessageConverter只支持APPLICATION_JSON类型,所以springboot没有找到合适的HttpMessageConverter,于是报出了上面的异常。

feign默认的Decoder为SpringDecoder:

public class SpringDecoder implements Decoder {

	private ObjectFactory<HttpMessageConverters> messageConverters;

	public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
		this.messageConverters = messageConverters;
	}
}

我们看一下默认的messageConverters

解决方案

解决该问题,只要添加MediaType.TEXT_PLAIN类型的支持即可

方案一

仅仅在该FeignClientMediaType.TEXT_PLAIN的支持,不影响其他的client。

@FeignClient(name = "test", url = "http://localhost:8080", configuration = TestClient.FeignTestConfiguration.class)
public interface TestClient {
    @GetMapping("/api/test")
    BaseResp<String> test();

    class FeignTestConfiguration {
        @Bean
        public Decoder textPlainDecoder() {
            return new SpringDecoder(() -> new HttpMessageConverters(new CustomMappingJackson2HttpMessageConverter()));
        }
    }

    class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
        @Override
        public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
            super.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN));
        }
    }
}

调用接口,查看该FeignClientDecoder

此时调用成功。

方案二

全局修改,使所有的调用都支持TEXT_PLAINContent-Type

@Configuration
public class TestConfig {

    @Bean
    public MappingJackson2HttpMessageConverter customMappingJackson2HttpMessageConverter() {
        return new CustomMappingJackson2HttpMessageConverter();
    }

    static class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
        public CustomMappingJackson2HttpMessageConverter() {
            setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN));
        }
    }
}

方案三

我们也可以实现WebMvcConfigurer下面接口来实现对应功能。

/**
	 * Configure the {@link HttpMessageConverter}s to use for reading or writing
	 * to the body of the request or response. If no converters are added, a
	 * default list of converters is registered.
	 * <p><strong>Note</strong> that adding converters to the list, turns off
	 * default converter registration. To simply add a converter without impacting
	 * default registration, consider using the method
	 * {@link #extendMessageConverters(java.util.List)} instead.
	 * @param converters initially an empty list of converters
	 */
	default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
	}

	/**
	 * A hook for extending or modifying the list of converters after it has been
	 * configured. This may be useful for example to allow default converters to
	 * be registered and then insert a custom converter through this method.
	 * @param converters the list of configured converters to extend.
	 * @since 4.1.3
	 */
	default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
	}

文章作者: shiv
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 shiv !
评论
  目录