Open alex-vukov opened 3 weeks ago
Although there's a error log be printed, your code works as you want. But actually it should print some details message, not just java.io.IOException: null
('null' should be a detail message like Client reset the stream before the request was fully read
, I think it will be added later). And why I said it's no bug:
emitter.send
. Your try-catch code surround it can't catch this IOException.When the framework/tomcat is handling some exceptions, it will print error logs even if they are handled as expected. Don't worry, these logs are normal.
This log doesn't show up on HTTP1.1 or on Jetty so it's a bug in the way the exception from Tomcat is handled. The user of the SseEmitter should be able to catch the exception in case any additional processing is needed. I am able to catch the IOException when on HTTP1.1 but I am not able to catch it using HTTP2.0 so it's definitely inconsistent.
This log doesn't show up on HTTP1.1 or on Jetty
This log show in both HTTP1.1 and HTTP2.0 when using tomcat. In your example projcet, I disable http2, exception still be logged. Config is:
server.http2.enabled=false
spring.application.name=demo
#server.ssl.key-store-type=PKCS12
#server.ssl.key-store=classpath:localhost.p12
#server.ssl.key-store-password=
#server.ssl.key-alias=localhost
The user of the SseEmitter should be able to catch the exception in case any additional processing is needed.
This is a misnomer.
emitter.onError((ex) -> {System.out.println("Error BEEEE");});
In emitter.onError
, we do our own business logic. After that, tomcat still need the exception to control request/response.
And I mean the tomcat code is like (It's actually a long processing chain, here I've simply represented as):
try {
} catch(IOException e) {
// invoke developer's onError() method to process developer's business logic. This doesn't affect tomcat's exception handling processing
log.error(e); // tomcat print log, but jetty not
// close sse base on exception
}
In jetty, log was's show becaust it didn't print log, not your code catched it.
In my opinion, it's similar to IOException: Broken pipe
when using GET/POST http method. Do you know this one?
The exception is correctly handled, and this log can be ignored as IOException: Broken pipe
.
The crash happens on HTTP2 every time the browser issues an EventSource close() and can be reproduced with this repo:
https://github.com/alex-vukov/spring-sse-issue
You can test by starting the application, opening the following URL from the browser
https://localhost:8080/sse
and after you receive some data clicking on the browser's stop button. It can also be reproduced in JavaScript with EventSource close(). The error happens only with the integrated Tomcat server and only over HTTP2. It doesn't happen with Jetty (you can test by switching thepom.xml
withpom-jetty.xml
). This is the exception which breaks the app and it is unhandled even though in the code I haveemitter.send
wrapped in try-catch: