Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server-Sent-Events (SSE) and HTTPS

I have a spring-boot backend and wanted to create a SSE endpoint, sample:

@CrossOrigin(origins = "http://localhost:4200") // Angular Dev-Server
@GetMapping(path = "/stream-flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamFlux() {
    return Flux.interval(Duration.ofSeconds(1))
            .map(sequence -> "data: Flux - " + LocalTime.now().toString() + "\n\n")
            .doOnSubscribe(subscription -> {
                System.out.println("SSE-Stream started.");
            })
            .doOnNext(value -> {
                System.out.println("SSE-Value sent: " + value);
            })
            .doOnError(error -> {
                System.out.println("SSE-Error: " + error.getMessage());
            })
            .doOnComplete(() -> {
                System.out.println("SSE-Stream complete.");
            });                
}

Now, this example works perfect with an http-call (and the respective spring-server settings), tested with CURL.

curl -v http://localhost:8080/stream-flux

But when I wanted to switch to https (of course with the right spring-boot server settings)

tested with the following call:

curl -k -v https://localhost:<ssl-port>/stream-flux

The values from the event doesn't come at all with https. I am using a self-signed certificate.

And the CURL-answer is confusing to me:

* schannel: remote party requests renegotiation
* schannel: renegotiating SSL/TLS connection
* schannel: SSL/TLS connection renegotiated
* Request completely sent off

Any approach to tackling this issue is highly appreciated.

like image 319
Tony Avatar asked Nov 22 '25 21:11

Tony


1 Answers

Spring Boot Logging Filter Blocks SSE (Server-Sent Events)

My Spring Boot application has a additional Filter that logs incoming REST requests and responses. It uses ContentCachingRequestWrapper and ContentCachingResponseWrapper to capture requests and response bodies.

Original Problem: Standard REST endpoints work fine, but SSE (text/event-stream) endpoints never send data to the client.

Cause: ContentCachingResponseWrapper buffers the entire response before passing it downstream. Since SSE is a continuous stream, it never completes, so the client never receives data.

Solution: Exclude SSE from logging To prevent this issue, I modified my filter to bypass SSE requests:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    // Skip logging for SSE responses
    if (httpRequest.getContentType() == null || httpRequest.getContentType().equals(MediaType.TEXT_EVENT_STREAM_VALUE)) {
        chain.doFilter(request, response);
        return;
    }

    ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(httpRequest);
    ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(httpResponse);

    chain.doFilter(wrappedRequest, wrappedResponse);

    logRequestAndResponse(wrappedRequest, wrappedResponse);

    wrappedResponse.copyBodyToResponse();
}

Now, SSE responses are streamed directly without being cached, issue ist fixed.

Hope this helps someone facing the same problem! 😊

like image 161
Tony Avatar answered Nov 24 '25 11:11

Tony