Spring 解码时启动 Webflux 处理程序错误 XML 向 Mono 或 Flux 对象请求正文内容

Spring Boot Webflux Handler errors when decoding XML request body content to Mono or Flux object

我一直在尝试实现 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 class,但 BodyExtractors 正在过滤解码器并匹配 class 和 mime 类型。对于 Json,它正在查看 Java class 并在比较 MIME 类型之前尝试从中获取映射。在调试的深处,当它仍在尝试将 class 映射到对象映射器时,它会崩溃。

我目前正在使用 Spring 引导版本 2.3.4-RELEASE 和 Java8。文档提到如果您的 class 路径中有 JaxB,那么对于 XML 它应该使用 Jaxb2XmlDecoder 和 Endoder 作为默认编解码器。如果您的 class 路径上有 Jackson,它也会使用 Jackson。我确实碰巧都减去了 jackson-dataformat-xml 依赖项。我很确定它要么是我的测试配置,要么是 WebFluxConfigurer,我尝试为 jaxb2Decoder 和编码器设置默认编解码器。我也确实尝试添加 jackson-dataformat-xml 依赖项,但这也不起作用。这是我尝试使用的 webconfig,但在尝试使用 Json 解码器解码 application/xml 的 mime 类型时仍然崩溃。这是网络配置:

@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 class 的 readWithMessageReaders 方法中时,函数中有一个过滤器可以循环访问消息阅读器和解码器。当它到达 DecoderHttpMessageReader,Jackson2JsonDecoder 时,它开始尝试解码请求。不知道为什么,因为调试器中的 mime 类型显示 application/xml.

有没有人对如何调试这段代码有任何建议:

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

这是在使用上面的代码进行单元测试期间死掉的地方。我试过调试,但当我太深入时它只会停止测试。我只知道它在尝试匹配编解码器时正在经历 Java 类型。大多数编解码器只是立即 return,但是 Json 和 XML 解码器正在尝试获取 Java class 属性并且令人窒息。 class 是具有所有正确注释的 JaxB class。 WebTestClient 将 class 编码为 XML 进行测试没有问题。那么为什么处理程序不能将主体转换为单声道呢?该代码语句没有抛出任何内容。

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

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

旧 return 语句:

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

新 return 语句:

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

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