使用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'吗?
答案 0 :(得分:1)
Spring Framework目前不支持Jackson XML-请参见the dedicated issue。同时,您可以将Jaxb与Jaxb2XmlEncoder
和Jaxb2XmlDecoder
一起使用。
答案 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 请求。