将XML请求主体内容解码为Mono或Flux对象时,Spring Boot Webflux Handler错误

问题描述

我一直在尝试实现Spring反应式路由器和处理程序,而不是MVC控制器。看起来很简单,但是我的WebTestClient测试由于500 Internal Server Error而失败。测试的代码短码。

@ContextConfiguration(classes = {FooRouter.class,FooServiceConfig.class,FoonHandler.class})
@WebFluxTest
public class FooHandlerTest {

@Test
public void testFooPost()  {
    webTestClient.post()
            .uri("/foot")
            .contentType(MediaType.APPLICATION_XML)
            .accept(MediaType.APPLICATION_XML)
            .body(Mono.just(foo),Foo.class)
            .exchange()
            .expectStatus().isCreated()
            .expectBody(Bar.class)
            .isEqualTo(bar);
}

在测试过程中,路由器工作正常并调用处理程序。当处理程序尝试从请求正文创建Mono时:

Mono<Foo> fooMono = request.bodyToMono(Foo.class);

该行杀死了单元测试,并且WebTestClient收到500状态代码。在调试期间,尽管mime类型是application / xml,并且确实映射了Java类,但BodyExtractors仍在过滤解码器并匹配类和mime类型。对于Json,它正在查看Java类,并在比较mime类型之前尝试从中获得映射。深入调试时,当它仍尝试将类映射到对象映射器时,它将崩溃。

我目前正在将Spring Boot版本2.3.4-RELEASE与Java8结合使用。文档中提到如果您的类路径中有JaxB,则对于XML,应使用Jaxb2XmlDecoder和Endoder作为默认编解码器。如果您在类路径中使用了Jackson,它也将使用Jackson。我确实碰巧都减去了jackson-dataformat-xml依赖项。我很确定这是我的测试配置,也可以是WebFluxConfigurer,我尝试为jaxb2Decoder和Encoder设置默认编解码器。我也曾尝试添加jackson-dataformat-xml依赖项,但这也不起作用。这是我尝试使用的webconfig,但是尝试使用Json解码器解码application / xml的mime类型仍然失败。这是webconfig:

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.registerDefaults(false);
        configurer.defaultCodecs().jaxb2Decoder(new Jaxb2XmlDecoder(MediaType.APPLICATION_XML));
        configurer.defaultCodecs().jaxb2Encoder(new Jaxb2XmlEncoder());
    }
}

我一直在调试并打印出请求对象消息阅读器,而Jaxb2XmlEncoder是xml mime类型的编解码器之一。这是JSON和XML解码器的打印消息:

Message Reader: org.springframework.http.codec.DecoderHttpMessageReader@5b2cea27
    DecoderHttpMessageReader Decoder: org.springframework.http.codec.json.Jackson2JsonDecoder@87b7472
        Mime Type: application/json
        Mime Type: application/*+json
Message Reader: org.springframework.http.codec.DecoderHttpMessageReader@198a86e1
    DecoderHttpMessageReader Decoder: org.springframework.http.codec.xml.Jaxb2XmlDecoder@50cb41d0
        Mime Type: application/xml
        Mime Type: text/xml
        Mime Type: application/*+xml

在BodyExtractors类的readWithMessageReaders方法中,函数中有一个筛选器,该筛选器遍历消息阅读器和解码器。当到达DecoderHttpMessageReader,Jackson2JsonDecoder时,它开始尝试对请求进行解码。不知道为什么,因为调试器中的mime类型显示application / xml。

有人对如何调试这段代码有任何建议吗?

Mono<Foo> fooMono = request.bodyToMono(Foo.class);

这是上面代码在单元测试期间死亡的地方。我已经尝试过调试,但是当我变得太深时,它只会停止测试。我只知道它在尝试匹配编解码器时正在经历Java类型。大多数编解码器会立即返回,但是Json和XML解码器正在尝试获取Java类属性并且令人窒息。该类是具有所有正确批注的JaxB类。 WebTestClient毫无疑问地将类编码为XML以进行测试。那么,处理程序为什么不能将主体转换为单声道呢?该代码语句什么也没扔。

解决方法

我知道这是我的设置,单元测试未显示正确的问题。

我的return语句实际上在获取正文内容时导致错误。

旧的退货声明:

return created(URI.create(response.getDocument().getPath()))
    .bodyValue(Mono.just(response));

新的退货声明:

return created(URI.create(response.getDocument().getPath()))
    .body(Mono.just(response),Response.class);

看到bodyValue和body的区别了吗?这导致请求主体无法转换为Mono。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...