Spring WebFlux:HttpWebHandlerAdapter-建立的连接被中止

时间:2018-09-05 09:20:47

标签: spring reactive-programming spring-webflux project-reactor

我正在使用Spring WebFlux发布/接收服务器已发送事件。在发布方面,代码如下。然后,在一个测试用例中,我循环10次以调用“发布”以发送消息。

public ValidationEventPublisher() {
    this.processor = DirectProcessor.<ExternalEvent>create().serialize();
    this.sink = processor.sink();
}

@RequestMapping(value = "/ssp/common/v1/eventstream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<ExternalEvent>> sse() {
    return processor.map(e -> ServerSentEvent.builder(e).id(String.valueOf(msgId.incrementAndGet())).build())
            .onBackpressureBuffer();
}

public void publish(ValidationEvent validationEvent)
{
    log.info("Published Validation event...");
    sink.next(validationEvent);
}

在接收方,代码是:

final Flux<Object> stream = WebClient.builder()
            .baseUrl(sspUrl + "/ssp/common/v1/eventstream")
            .defaultHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((username + ":" + password).getBytes(UTF_8)))
            .build()
            .get()
            .retrieve()
            .bodyToFlux(ServerSentEvent.class)
            .filter(e -> e.id() != null)
            .flatMap(e -> Mono.just(e.data()))
            .doOnError(e -> handleServerDown(e))
            .repeat();

    stream.subscribe(e -> processEvent(e));

所以,问题是我只能收到第一条消息,此后总是出现异常。

- Published Validation event...
- Received validation event: {"messageId":"867b5ced-...}
- Published Validation event...
- Published Validation event...
2018-09-05 11:07:43,596 ERROR [reactor-http-nio-6] [] [] 
[org.springframework.web.server.adapter.HttpWebHandlerAdapter:213] - 
Unhandled failure: An established connection was aborted by the software in 
your host machine, response already set (status=null)
2018-09-05 11:07:43,597  WARN [reactor-http-nio-6] [] [] 
[org.springframework.http.server.reactive.ReactorHttpHandlerAdapter:76] - 
Handling completed with error: An established connection was aborted by the 
software in your host machine
...

我花了很长时间进行一些研究,但找不到相关信息。 请注意,我在一个测试用例中运行双方,这意味着它们在同一进程和JVM中。我认为这并不重要,但以防万一。

我发现原因是“取消”被发送出去了。但为什么?例如,如果我在接收方添加“ doOnCancel”,则可以看到它被称为。

2 个答案:

答案 0 :(得分:0)

使用spring-boot-starter-parent 2.1.0.RELEASE我遇到了类似的问题。 尝试在端口8080和8081的客户端上运行以下服务

@SpringBootApplication
public class ServiceApplication {

    @Bean
    RouterFunction<ServerResponse> routes(Handler handler) {
        return route(GET("/there").and(accept(MediaType.TEXT_EVENT_STREAM)), handler::all);
    }

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

    @Component
    class Handler {
        public Mono<ServerResponse> all(ServerRequest request) {
            Flux<String> aFlux = Flux.range(0, 1000).map(i -> UUID.randomUUID().toString());
            return ok().contentType(MediaType.TEXT_EVENT_STREAM).body(aFlux, String.class);
        }
    }   
}

@SpringBootApplication
public class ClientApplication {

    @Bean
    RouterFunction<ServerResponse> routes(Handler handler) {
        return route(GET("/here").and(accept(MediaType.TEXT_EVENT_STREAM)), handler::all);
    }

    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }

    @Component
    class Handler {
        public Mono<ServerResponse> all(ServerRequest request) {
            Flux<String> resp = WebClient.create("http://localhost:8080")
                                        .get()
                                        .uri("/there")
                                        .accept(MediaType.TEXT_EVENT_STREAM)
                                        .retrieve()
                                        .bodyToFlux(String.class);

            return ok().contentType(MediaType.TEXT_EVENT_STREAM).body(resp, String.class);
        }
    }   
}

现在多次执行curl -H“ Accept:text / event-stream”“ http://localhost:8081/here”,该服务有时会出错:

oswsadapter.HttpWebHandlerAdapter:[f903e4b6]错误[java.io.IOException:您的主机计算机中的软件中止了已建立的连接],用于HTTP GET“ / there”,但ServerHttpResponse已经提交(200 OK)

答案 1 :(得分:0)

问题发布已经有一段时间了。现在我认为问题是在我处理消息时引起的一些异常,例如NPE在processEvent中。如果在processEvent中添加一个野生try ... catch,则很容易证明这一点。