ralscha / sse-eventbus

EventBus library for sending events from a Spring appliction to the web browser with SSE
Apache License 2.0
79 stars 26 forks source link

EventSource's response has a MIME type ("text/plain") instead of "text/event-stream" #25

Closed eltishehu closed 3 months ago

eltishehu commented 3 months ago

I am encountering an issue when using the SseEventBus library in my Spring Boot application to show a progress bar for an upload process. The error message I receive in the browser is:

EventSource's response has a MIME type ("text/plain") that is not "text/event-stream". Aborting the connection.

I have followed all the steps in the README file and this used to work perfectly fine before upgrading to Spring Boot 3.

I have added the @EnableSseEventBus annotation to my Spring application class.

This is my controller method:

    @GetMapping(path = "/register/{eventType}/{clientId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter registerEvent(@PathVariable("eventType") String eventType,
                                    @PathVariable("clientId") String clientId,
                                    HttpServletResponse response) {
        response.addHeader("Cache-Control", "no-store");
        response.addHeader("Connection", HttpHeaders.KEEP_ALIVE.toLowerCase());
        response.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);

        return this.eventBus.createSseEmitter(clientId, 30_000L, eventType);
    }

This is my DataEmitterService:

@Component
public class ServerSentEventService {

    private final ApplicationEventPublisher eventPublisher;

    public ServerSentEventUtil(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void sendProgress(String clientId, String eventType, StatusEnum status, double percentage) {
        ServerSentEventProgress progressData = ServerSentEventProgress.builder()
                .status(status)
                .percentage(Math.round(percentage)).build();

        SseEvent event = SseEvent.builder()
                .event(eventType)
                .data(progressData)
                .addClientId(clientId).build();

        eventPublisher.publishEvent(event);
    }

    public void sendEvent(String clientId, String eventType, Object data) {
        SseEvent event = SseEvent.builder()
                .event(eventType)
                .data(data)
                .addClientId(clientId).build();

        eventPublisher.publishEvent(event);
    }
}

These are the methods on the client side:

private getEventSource(clientId: string, eventType: string): EventSource {
    if (!this.eventSource) {
      this.eventSource = new EventSource(`${this.sseApi}/register/${eventType}/${clientId}`);
    }

    return this.eventSource;
}

public subscribe(eventType: string, clientId: string): Observable<any> {
    const eventSource = this.getEventSource(clientId, eventType);

    eventSource.onmessage = function(event) {
      console.log('Message from server ', event.data);
      // Update progress bar based on event data
    };

    eventSource.onerror = function(err) {
      console.error('EventSource failed:', err);
    };

    return new Observable((observer: Observer<any>) => {
      const eventListener = (event: any) => {
        this.zone.run(() => observer.next(JSON.parse(event.data)));
      }

      eventSource.addEventListener(eventType, eventListener);
        return () => {
          eventSource.removeEventListener(eventType, eventListener);
        }
    })
    .pipe(
      share()
    );
}

public unsubscribe(eventType: string, clientId: string): void {
    this.eventSource.close();
    this.eventSource = null;

    this.http.get(`${this.sseApi}/unregister/${clientId}`).subscribe();
}

This is the error on my browser: image

If there are any configurations or specific methods in SseEventBus to ensure the correct MIME type is set, please let me know. Any guidance or fixes would be greatly appreciated.

Thank you for your assistance.

ralscha commented 3 months ago

Hi

I tested it with the demo app (Spring Boot 3.3.0 and sse-eventbus 2.0.1) just now and with this application it looks okay.

Can you upgrade the sse-eventbus library to 2.0.1 and try it without setting the contentType. This should not be necessary. Spring should set the correct content type.

// response.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);
eltishehu commented 3 months ago

Hello,

Thank you for replying.

I get the same result with sse-eventbus 2.0.1 and removing the explicit setting for content type.

image

I have debugged the issue and have tracked it down to this method: org.springframework.web.servlet.mvc.method.annotation.SseEmitter.SseEventBuilderImpl#saveAppendedText

This is Spring's class and it sets the event's type to text/plain:

image

But I checked the old version I was using and the code seems the same on Spring's side.

image (2)

Not sure what has changed now.

Do you have any idea?

ralscha commented 3 months ago

I've created an example project based on your code and it works fine. It always sends back the correct mime type text/event-stream.

https://github.com/ralscha/sse-spring-demo2

Could there be some other component/service in your system that handles the response and somehow changes the mime type.

eltishehu commented 3 months ago

I do have several filters in my application for handling the request/response, but none of them manipulates the content type. I have checked them all and nothing suspicious happen there to have anything to do with this issue. This used to work fine before upgrading to Spring Boot 3. I suspect it is a library compatibility issue.

ralscha commented 3 months ago

Very mysterious. I've scrolled through the issues of the Spring framework, but there are no mentions of a similar problem: Spring Framework Issues

eltishehu commented 3 months ago

Apparently the issue was with the Spring Boot version. Upgrading from 3.2.3 to 3.3.0 solved the issue. 🤔

ralscha commented 3 months ago

Interesting. Looking through the changelog of Spring Boot but can't find anything regarding server-sent events. https://github.com/spring-projects/spring-boot/releases

Glad to hear that it works now. Thanks for the feedback.

eltishehu commented 3 months ago

Thank you for taking the time to answer and looking into the issue. Appreciate it. Have a great one!