簡體   English   中英

如何在 spring 啟動應用程序中關閉客戶端 sse 連接

[英]How to close client sse connection in spring boot application

我有一個 spring 啟動應用程序,我必須使用 SSE 連接到一些外部服務。 WebClient 建立連接,然后我使用 Flux 來讀取響應。 一切正常,但問題是連接保持打開狀態,因為該過程並非旨在每次在該第 3 方服務中達到終點。 我想作為客戶端手動關閉連接,因為我知道這個連接應該何時完成。 我怎樣才能做到這一點?

建立連接:

private Flux<ServerSentEvent<String>> connect(String accessToken) {
    TcpClient timeoutClient = createTimeoutClient();
    ReactorClientHttpConnector reactorClientHttpConnector = new ReactorClientHttpConnector(HttpClient.from(timeoutClient));
    String url = npzServerBaseUrl+uniqueCodePath;
    WebClient client = WebClient
            .builder()
            .clientConnector(reactorClientHttpConnector)
            .defaultHeader(HttpHeaders.AUTHORIZATION, Naming.TOKEN_PREFIX + accessToken)
            .baseUrl(url)
            .build();

    ParameterizedTypeReference<ServerSentEvent<String>> type
            = new ParameterizedTypeReference<ServerSentEvent<String>>() {};
    return client.get()
            .retrieve()
            .onStatus(HttpStatus::is4xxClientError, clientResponse -> {
                String msg = "Error from server: "+clientResponse.statusCode().toString();
                        //invalidate access token
                        if (clientResponse.statusCode().value()==401) {
                            //remove invalid token and connect again
                            loginContext.invalidToken(accessToken);
                            return Mono.error(new InvalidNpzToken(msg));
                        }
                        return Mono.error(new IllegalStateException(msg));
                    }
            )
            .onStatus(HttpStatus::is5xxServerError, clientResponse ->
                    Mono.error(new IllegalStateException("Error from server: "+clientResponse.statusCode().toString()))
            )
            .bodyToFlux(type);
}

private TcpClient createTimeoutClient() {
    return TcpClient.create()
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SECONDS*1000)
            .option(EpollChannelOption.TCP_USER_TIMEOUT, SECONDS*1000)
            .doOnConnected(
                    c -> c.addHandlerLast(new ReadTimeoutHandler(SECONDS))
                            .addHandlerLast(new WriteTimeoutHandler(SECONDS)));
}

處理內容:

Flux<ServerSentEvent<String>> eventStream = connect(accessToken);

    eventStream.subscribe(
            content -> {
                log.info("Time: {} - event: name[{}], id [{}], content[{}] ",
                    LocalTime.now(), content.event(), content.id(), content.data());
                if ("uuid".equals(content.event().trim())) {
                    listener.receivedUniqueCode(content.data().trim());
                } else if ("code".equals(content.event().trim())) {
                    listener.receivedCode(content.data().trim());
                }
            },
            (Throwable error) -> {
                if (error instanceof InvalidToken) {
                    log.error("Error receiving SSE", error);
                    //let's retry connection as token has expired
                    getCode(request, listener);
                }
            },
            () -> log.info("Connection closed!"));

我期望的是我可以調用 connection.close() 或類似的東西,並且連接將被關閉。

謝謝

如果需要,請提供更多信息。

進口:

import io.netty.channel.ChannelOption;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.TcpClient;

Spring 開機:

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>

eventStream.subscribe()返回一個reactor.core.Disposable

您可以在其上調用dispose()以取消訂閱和底層資源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM