org.springframework.web.reactive.function.UnsupportedMediaTypeException:bodyType

时间:2019-07-15 04:29:49

标签: java spring spring-boot jackson spring-webflux

使用Java 11,SpringBoot 2,WebFlux,WebClient和Jackson

尝试使用Spring WebClient消耗返回XML的Web服务端点,内容类型:'text / xml; charset = UTF-8'

项目的pom.xml中的

Jackson XML依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.9</version>
</dependency>

可触发对外部API的请求并构建响应的WebClient代码:

        WebClient.builder()
                .baseUrl(url)
                .build()
                .get()
                .uri(builder.toUriString(), 1L)
                .accept(TEXT_XML)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML_VALUE)
                .acceptCharset(Charset.forName("UTF-8"))
                .exchange()
                .flatMap(x -> x.bodyToMono(ServiceResponse.class))
                .flatMap(x -> buildResponse(x));

ServiceResponse类(一个简单的POJO):

public class ServiceResponse {

    private String ack;
    private String version;
    private String timestamp;
// .. getters and setters

结果错误:

  

org.springframework.web.reactive.function.UnsupportedMediaTypeException:   不支持的内容类型'text / xml; charset = UTF-8'   bodyType = com.sample.service.model.ServiceResponse位于   org.springframework.web.reactive.function.BodyExtractors.lambda $ readWithMessageReaders $ 12(BodyExtractors.java:201)   〜[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE]在   java.base / java.util.Optional.orElseGet(Optional.java:369)〜[na:na]在   org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:197)   〜[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE]在   org.springframework.web.reactive.function.BodyExtractors.lambda $ toMono $ 2(BodyExtractors.java:85)   〜[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE]在   org.springframework.web.reactive.function.client.DefaultClientResponse.body(DefaultClientResponse.java:95)   〜[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE]在   org.springframework.web.reactive.function.client.DefaultClientResponse.bodyToMono(DefaultClientResponse.java:113)   〜[spring-webflux-5.1.8.RELEASE.jar:5.1.8.RELEASE]

如何正确使用响应类型:内容类型'text / xml; charset = UTF-8'吗?

5 个答案:

答案 0 :(得分:1)

Spring Framework目前不支持Jackson XML-请参见the dedicated issue。同时,您可以将Jaxb与Jaxb2XmlEncoderJaxb2XmlDecoder一起使用。

答案 1 :(得分:1)

添加

.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML) 

为我工作。 MediaType表示HTTP规范中定义的Internet媒体类型。 供参考:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/MediaType.html

当我尝试在Spring Webflux中使用WebTestClient编写tc时,遇到了此错误。 单元测试在以下部分中:

@Test
 public void testGetJobSummariesResBody() throws Exception{
 List<JobSummary> responseBody =
                testClient
                .get().uri("<uri-name>")
                .accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
                .header(APPNAME_HEADER, "<header-name>")
                .exchange()
                .expectStatus().isOk()
                .expectBodyList(JobSummary.class)
                .returnResult()
                .getResponseBody();

        assertNotNull(responseBody.get(0).getJobType());
        assertNotEquals(0,responseBody.size());
    }

答案 2 :(得分:0)

当我尝试返回“纯文本/文本”但对象被解析为json格式(因此不是真正的文本)时,我遇到了类似的情况。我认为spring正在对响应的内容类型和所设置的主体进行一些验证。我的实际回答是这样的:

Mono.just(quote.getQuote())
                .flatMap(s -> ServerResponse.ok()
                        .contentType(MediaType.TEXT_PLAIN)
                        .syncBody(s)
                );

但也可以接受的是:

Mono.just(jsonQuote)
                .flatMap(s -> ServerResponse.ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .syncBody(s)
                );

答案 3 :(得分:0)

就我而言,问题是我忘记设置 Accept 标头,服务器的默认行为是返回 XML。
将其设置为 MediaType.APPLICATION_JSON 解决了问题,服务器开始返回 JSON。

答案 4 :(得分:-1)

另一种引发混淆的 UnsupportedMediaTypeException 的情况。 让我们假设有生产 api 监听 http/80 和 https/443。然而,它的配置使得没有内容通过 http 提供。相反,这会返回 HTTP 301 重定向消息,其中包含一些内容类型为 text/html 的 html 内容。默认情况下,WebClient 不遵循 301 重定向,而是尝试将返回的 html 消息解析为假定的类。这显然失败并产生 UnsupportedMediaTypeException 异常。 Postman 默认遵循 301 重定向并以完全透明的方式执行,这可能会进一步混淆这一事实。给人留下通过 http 请求获得预期内容的印象。

解决方案:使用 https 请求。