How to make Server sent events (SSE) work trough Z

2019-07-17 15:01发布

问题:

I have some issues getting SSE working trough my zuul reverse proxy

My setup:

Spring boot version: 2.1.1.RELEASE
Spring cloud dependencies: Greenwich.RC1
Angular-cli: Angular 7
Kotlin: 1.3.11
os: Linux

I have a small rest service that uses SSE

@SpringBootApplication
@RestController
@CrossOrigin("http://localhost:19195")
class RestApplication {
    private final val processor = DirectProcessor.create<Int>().serialize()
    private final val sink = processor.sink()
    private final val counter = AtomicInteger()

    @GetMapping("/stream")
    fun stream(): Flux<ServerSentEvent<Int>> {
        println("Stream connected")
        return processor.map { n -> ServerSentEvent.builder<Int>(n).build() }
    }

    @GetMapping("/increment")
    fun sink() {
        sink.next(counter.incrementAndGet())
    }

}

This works fine if my EventSource connects directly to it from my angular service:

const sse = new EventSource('http://localhost:8080/stream');
sse.onopen = (event) => {
  console.log('OnOpen ' + event);
};
sse.onmessage = (event) => {
  console.log(event);
sse.onerror = (error) => {
  console.log(error);
};

If I hit the /increment endpoint the service receives sse events with incrementing values.

Now with this zuul config:

zuul:
 sensitive-headers:
 routes:
  rest:
    path: /rest/**
    url: http://192.168.75.90:8080
 add-proxy-headers: true
 add-host-header: true

Angular service updated to go via proxy:

const sse = new EventSource('rest/stream');
sse.onopen = (event) => {
  console.log('OnOpen ' + event);
};
sse.onmessage = (event) => {
console.log(event);

};
sse.onerror = (error) => {
console.log(error);
};

Now my angular service, connects to the stream, waits for the default zuul timeout (10 seconds) then returns a 406 and reconnects. That is if i have no data.

If i have data in the sink, it connects to the sse stream and nothing happens as long as i am pushing data onto the stream. When I stop pushing data EventSource waits for zuul timeout (10 seconds) then receives all data on stream and disconnects/reconnects.

I am aware that zuul 1.x does not support SSE, but I was hoping the zuul bundeled with spring boot 2.1.1 would.

Anyone know?

回答1:

The problem is you are using Zuul 1.x, even if you are using springboot version 2.x. I had the same problem and as it seems Spring Cloud Netflix will not support Zuul 2.x currently and in the future. So when you are using the spring cloud environment, i would suggest to switch to spring-cloud-gateway. I am using it with SSE and i am satisfied with the current solution. Another choice would be to switch over to Zuul 2.0 directly.