marcospds / ngx-sse-client

An SSE (server sent event) client alternative solution for Angular
MIT License
22 stars 3 forks source link

No events received from Spring Flux endpoint. #2

Closed seraphinek closed 3 years ago

seraphinek commented 3 years ago

Hello,

I've ran into a security related roadblock with basic EventSource solution (couldn't add security headers) and I've decided to try ngx-sse-client, however I fail to receive any events when creating a SSE connection via sseClient.stream (GET method). Connection is opened correctly, I see that my backend service is producing results periodically, as usual. The only difference is these results are not emitted to the frontend. Note that when I open my SSE connection by just calling the endpoint in the browser (or via regular EventSource) events are received normally, so I think problem may be in: a) how connection is created in the sseClient b) how data is produced by the service (different approach needed for sseClient)

What I've tried:

const headers = new HttpHeaders().set('accept', 'text/event-stream');

const sseObservable = this.sseClient.stream(url, {
    responseType: 'text',
    keepAlive: false
}, {headers}, 'GET').subscribe(text => {
    console.log(text);
});
const sseObservable = this.sseClient.stream(url, {
    responseType: 'event', keepAlive: true
}, {headers}, 'GET').subscribe(event => {
    if (event.type === 'error') {
        const errorEvent = event as ErrorEvent;
        console.log('ERROR' + errorEvent.error);
    } else {
        const messageEvent = event as MessageEvent;
        console.log('DATA' + messageEvent.data);                
    }
});

While doing this works (ofc except of the headers part):

const eventSource = new EventSource(url);
this.eventSource.onmessage = (event) => {
    console.log(JSON.parse(event.data));
};
this.eventSource.onerror = (error) => {
  if (this.eventSource.readyState === 0) {
      this.eventSource.close();       
  } else {
      console.log('EventSource error: ' + error);
  }
};

I've tried to reproduce headers as closely as possible to match what EventSource does, but no luck. The only difference is type of connection (eventsource vs xhr (in ngx-sse-client)).

For the record, my Flux endpoint:

@PostMapping(path = "/v1/sse/tasks")
public Flux<ServerSentEvent<List<String>>> getData(@RequestParam Request request) {
    return Flux.interval(Duration.ofSeconds(10))
            .map(i -> this.service.call(request))
            .map(data -> ServerSentEvent.builder(data).event("message").build());
}

Any ideas what could be the problem?

rubinhos commented 3 years ago

Hi there,

Thank you for reaching me, I really don't know what could cause this. I use this lib on my Spring application as well, but I don't use webflux yet. I will try to reproduce this problem and as soon as I resolve it, I will contact you here.

rubinhos commented 3 years ago

Hi @seraphinek ,

I just tried to simulate the problem, but I couldn't find a way to reproduce it. I just created a simple Spring application with WebFlux and created the controller as bellow (very close to your code, but I changed to GetMapping):

@RestController
@RequestMapping(path = "demo")
@CrossOrigin
public class DemoController {

    @GetMapping(path = "/v1/sse/tasks")
    public Flux<ServerSentEvent<List<String>>> getData() {
        return Flux.interval(Duration.ofSeconds(10)).map(this::serviceCall)
                .map(data -> ServerSentEvent.builder(data).event("message").build());
    }

    private List<String> serviceCall(Long interval) {
        return List.of(String.format("Interval %d - %s!", interval, LocalTime.now().toString()));
    }

}

On the client side (as I am using the ServerSentEvent, I need to use the event response type):

constructor(private sseClient: SseClient) {
  const subscribe = this.sseClient.stream(this.url, { responseType: 'event' }).subscribe((e) => {
    if (e.type === 'error') {
      const message = (e as ErrorEvent).message;
      console.error(`ERROR: ${message}`);
    } else {
      console.info(`Data received: ${(e as MessageEvent).data}`);
    }
  });
}

And it's working fine for me: Screenshot from 2021-08-17 10-58-43

Have you been able to move forward with your project?

seraphinek commented 3 years ago

Hello, thanks for your response and time spent on this problem. Looks like it must be somehow caused by our internal configuration, tough it is yet to be investigated what causes it. In the end due to other concerns we've decided to not use SSE and instead do regular polling via httpClient, but if SSE approach will be again considered, I will investigate the problem and let you know what may have caused it.

EDIT: FYI Snippet with 'PostMapping' I've attached was of course typo on my side, we've tested also with @GetMapping.