使用 Spring WebFlux 客户端使用 REST 端点时出错

Error while consuming REST Endpoint using Spring WebFlux Client

我刚开始使用 Spring reactor 3 (WebFlux)。当尝试使用 WebClient 将 REST 端点消耗到 return Flux 时,出现以下错误。

申请class:

@Bean
public WebClient client(){
    return WebClient.create("http://localhost:8080");
}

@Bean
CommandLineRunner demo(WebClient client){

    return args-> {
        client.get().uri("/reactive/zip-code")
                .accept(MediaType.APPLICATION_STREAM_JSON)
                .exchange()
                .flatMap(cr -> cr.bodyToFlux(ZipCode.class))
                .subscribe(System.out::println);
    };

}

build.gradle

    buildscript {
    ext {
        springBootVersion = '2.0.0.BUILD-SNAPSHOT'
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-  plugin:${springBootVersion}")
    }
  }

    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
    }
    dependencyManagement {
        imports {
            mavenBom "io.projectreactor:reactor-bom:Aluminium-SR1"
        }
    }

    dependencies {
        compile('io.projectreactor:reactor-core')
        compile('org.springframework.boot:spring-boot-devtools')
        compile('org.springframework.boot:spring-boot-starter-webflux')
        compileOnly('org.projectlombok:lombok')
        testCompile('org.springframework.boot:spring-boot-starter-test')
    }

错误:

2017-05-01 22:20:29.718 WARN 14417 --- [ctor-http-nio-2] i.n.c.AbstractChannelHandlerContext:异常“{}”[为完整堆栈跟踪启用 DEBUG 级别] 在处理以下异常时由用户处理程序的 exceptionCaught() 方法抛出:

java.lang.NoSuchMethodError: reactor.core.publisher.Flux.onErrorMap(Ljava/util/function/Function;)Lreactor/core/publisher/Flux;
    at org.springframework.http.codec.DecoderHttpMessageReader.read(DecoderHttpMessageReader.java:93) ~[spring-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.reactive.function.BodyExtractors.lambda$null(BodyExtractors.java:120) ~[spring-webflux-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at java.util.Optional.map(Optional.java:215) ~[na:1.8.0_111]
    at org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:183) ~[spring-webflux-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.reactive.function.BodyExtractors.lambda$toFlux(BodyExtractors.java:111) ~[spring-webflux-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.reactive.function.client.DefaultClientResponse.body(DefaultClientResponse.java:80) ~[spring-webflux-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.reactive.function.client.DefaultClientResponse.bodyToFlux(DefaultClientResponse.java:105) ~[spring-webflux-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at io.clapi.reactive.ReactiveApiApplication.lambda$null[=13=](ReactiveApiApplication.java:34) ~[main/:na]
    at reactor.core.publisher.MonoFlatMap$FlattenSubscriber.onNext(MonoFlatMap.java:132) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:119) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:178) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:119) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxRetryPredicate$RetryPredicateSubscriber.onNext(FluxRetryPredicate.java:78) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:370) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:99) ~[reactor-core-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at reactor.ipc.netty.channel.PooledClientContextHandler.fireContextActive(PooledClientContextHandler.java:84) ~[reactor-netty-0.6.1.RELEASE.jar:0.6.1.RELEASE]
    at reactor.ipc.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:524) ~[reactor-netty-0.6.1.RELEASE.jar:0.6.1.RELEASE]
    at reactor.ipc.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:125) ~[reactor-netty-0.6.1.RELEASE.jar:0.6.1.RELEASE]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:280) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:396) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:858) [netty-all-4.1.9.Final.jar:4.1.9.Final]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]

您不应该尝试自己管理 Reactor 依赖项,它由 Spring Boot 处理。从构建文件中删除 Reactor BOM。

这来自 API 反映在 Spring 代码库中的最新 Reactor SNAPSHOT 的变化。