服务器发送的事件异常导致无法捕获的 IllegalStateException
Sever Sent Event IOException causing uncatchable IllegalStateException
我有一个客户端接收 SseEmitter 的应用程序,
SseEmitter 会将 jms 消息中继到客户端。
客户端关闭连接(关闭浏览器)时出现问题。
将抛出 IOException,导致以下无法捕获的异常:
2019-01-24 12:33:59.163 ERROR 26516 --- [nio-8080-exec-6] o.a.catalina.connector.CoyoteAdapter : Exception while processing an asynchronous request
java.lang.IllegalStateException: Calling [asyncError()] is not valid for a request with Async state [MUST_DISPATCH]
at org.apache.coyote.AsyncStateMachine.asyncError(AsyncStateMachine.java:440) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:512) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.Request.action(Request.java:430) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:382) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:239) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:241) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.14.jar:9.0.14]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.14.jar:9.0.14]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
捕获 IOException 不会阻止抛出此异常。
我已经实施了一个解决方案,客户端发送请求以从将发送事件的发射器集合中删除他的发射器。
然而,在 client/browser 崩溃的情况下,仍会抛出此异常。
@Scheduled(fixedDelay = 2000L)
public void sendEvent() {
TextMessage message = null;
try {
message = messageBlockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(SseEmitter sseEmitter:emitterMap.values()) {
TextMessage finalMessage = message;
try {
sseEmitter.send(finalMessage.getText());
} catch (IOException e) {
sseEmitter.completeWithError(e);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
端点:
@CrossOrigin(allowCredentials = "true")
@RequestMapping(value = "/event", method = RequestMethod.GET)
public SseEmitter getEvent(HttpServletRequest request){
HttpSession session = request.getSession();
if(eventService.getEmitterMap().containsKey(session)){
System.out.println("existing sub found:"+session.getId());
return eventService.getEmitterMap().get(session);
}else{
final SseEmitter emitter = new SseEmitter(84000000000L);
eventService.register(session,emitter);
System.out.println("created new sub:"+session.getId());
return emitter;
}
}
经过进一步研究,这个异常可以归咎于 tomcat 中的一个错误。
https://github.com/spring-projects/spring-boot/issues/15057
为了解决这个问题,我已经从 tomcat 切换到 jetty。
我有一个客户端接收 SseEmitter 的应用程序, SseEmitter 会将 jms 消息中继到客户端。
客户端关闭连接(关闭浏览器)时出现问题。 将抛出 IOException,导致以下无法捕获的异常:
2019-01-24 12:33:59.163 ERROR 26516 --- [nio-8080-exec-6] o.a.catalina.connector.CoyoteAdapter : Exception while processing an asynchronous request
java.lang.IllegalStateException: Calling [asyncError()] is not valid for a request with Async state [MUST_DISPATCH]
at org.apache.coyote.AsyncStateMachine.asyncError(AsyncStateMachine.java:440) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:512) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.Request.action(Request.java:430) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:382) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:239) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:241) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) [tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.14.jar:9.0.14]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.14.jar:9.0.14]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
捕获 IOException 不会阻止抛出此异常。 我已经实施了一个解决方案,客户端发送请求以从将发送事件的发射器集合中删除他的发射器。
然而,在 client/browser 崩溃的情况下,仍会抛出此异常。
@Scheduled(fixedDelay = 2000L)
public void sendEvent() {
TextMessage message = null;
try {
message = messageBlockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(SseEmitter sseEmitter:emitterMap.values()) {
TextMessage finalMessage = message;
try {
sseEmitter.send(finalMessage.getText());
} catch (IOException e) {
sseEmitter.completeWithError(e);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
端点:
@CrossOrigin(allowCredentials = "true")
@RequestMapping(value = "/event", method = RequestMethod.GET)
public SseEmitter getEvent(HttpServletRequest request){
HttpSession session = request.getSession();
if(eventService.getEmitterMap().containsKey(session)){
System.out.println("existing sub found:"+session.getId());
return eventService.getEmitterMap().get(session);
}else{
final SseEmitter emitter = new SseEmitter(84000000000L);
eventService.register(session,emitter);
System.out.println("created new sub:"+session.getId());
return emitter;
}
}
经过进一步研究,这个异常可以归咎于 tomcat 中的一个错误。
https://github.com/spring-projects/spring-boot/issues/15057
为了解决这个问题,我已经从 tomcat 切换到 jetty。