AsyncHandlerInterceptor - 客户端关闭时未调用ASYNC调度程序请求

时间:2017-12-21 23:51:37

标签: spring-mvc asynchronous deferred-result

嗯,这是一种特殊的行为,我们的用例需要这种行为。 我们正在使用处理程序拦截器来增加活动请求数" at" preHandle"方法。在" afterCompletion"方法我们减少活动请求计数器。到现在为止还挺好。 同步通话很简单。但是在异步的情况下,存在第二个请求(DispatcherType:ASYNC),其用于递减计数器,而主请求(DispatcherType:REQUEST)用于递增计数器。我们检查调度员类型以避免双倍增量。所以很好。

在遇到有问题的客户端时发生问题,这些客户端在触发请求后断开连接。在这种情况下,当主请求进入服务器但在异步线程启动之前,客户端断开连接(如关闭浏览器)。在这种情况下,第二个请求(DispatcherType:ASYNC)根本没有被创建。 这种情况使计数器增加(主要要求)。 对于我们的用例,我们必须减少计数器,无论它是否为请求递增。 期待您的帮助/建议。提前谢谢。

其他详细信息: Spring Boot应用程序 Spring框架:4.3.4.RELEASE 雄猫:7 使用RestController 处理程序拦截器:AsyncHandlerInterceptor 在异步模式下,我们使用ResponseBodyEmitter将数据发送到客户端

登录服务器:

Exception in thread "pool-87-thread-1" java.lang.IllegalStateException: The request associated with the **AsyncContext has already completed processing**.
at org.apache.catalina.core.AsyncContextImpl.check(AsyncContextImpl.java:497)
at org.apache.catalina.core.AsyncContextImpl.getRequest(AsyncContextImpl.java:209)
at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:198)
at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:170)
at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:164)
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.dispatch(StandardServletAsyncWebRequest.java:123)
at org.springframework.web.context.request.async.WebAsyncManager.setConcurrentResultAndDispatch(WebAsyncManager.java:353)
at org.springframework.web.context.request.async.WebAsyncManager.access$200(WebAsyncManager.java:58)
at org.springframework.web.context.request.async.WebAsyncManager$7.handleResult(WebAsyncManager.java:416)
at org.springframework.web.context.request.async.DeferredResult.setResultInternal(DeferredResult.java:199)
at org.springframework.web.context.request.async.DeferredResult.setErrorResult(DeferredResult.java:214)
at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.completeWithError(ResponseBodyEmitterReturnValueHandler.java:219)
at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.completeWithError(ResponseBodyEmitter.java:204)
at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.sendInternal(ResponseBodyEmitter.java:169)
at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.send(ResponseBodyEmitter.java:159)
at net.atpco.pipeline.common.post.KryoResponseEmitterPostBox.send(KryoResponseEmitterPostBox.java:48)
at net.atpco.pipeline.common.post.KryoResponseEmitterPostBox.lambda$0(KryoResponseEmitterPostBox.java:37)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745) 

更新 在进一步的研究中,我在spring文档中发现了这一点......"请注意,当异步请求超时或完成网络错误时,HandlerInterceptor实现可能需要工作。对于这种情况,Servlet容器不会调度,因此不会调用postHandle和afterCompletion方法。相反,拦截器可以通过WebAsyncManager上的registerCallbackInterceptor和 registerDeferredResultInterceptor 方法注册以跟踪异步请求。无论异步请求处理是否开始,这都可以在preHandle的每个请求上主动完成。"这个deferredResultInterceptor似乎解决了这个问题。

0 个答案:

没有答案