gpt4 book ai didi

java - 使用 deferredResult 时,无法在提交响应后转发

转载 作者:行者123 更新时间:2023-11-30 03:20:09 25 4
gpt4 key购买 nike

为了实现长轮询,我尝试了不同的解决方案,但没有获得任何好的结果。

因此,我决定研究异步方法和 DeferredResult。这里我实现了 REST Controller 。

@Controller("sessionStateRest")
@RequestMapping("ui")
public class SessionStateRest extends BaseRestResource {

private final Queue<DeferredResult<ModelAndView>> mavQueue = new ConcurrentLinkedQueue<>();

/**
* Rest to check session state.
*
* @return string with session state
*/
@RequestMapping(value = "/session")
public @ResponseBody DeferredResult<ModelAndView> sessionState() {
final DeferredResult<ModelAndView> stateResult = new DeferredResult<>();
this.mavQueue.add(stateResult);
return stateResult;
}

@Scheduled(fixedDelay = 5000)
public void processQueue() {
for(DeferredResult<ModelAndView> result: mavQueue) {
if (null == SecurityHelper.getUserLogin()) {
result.setResult(createSuccessResponse("Invalidated session"));
mavQueue.remove(result);
}
}
}
}

按照想法,它应该每 5 秒处理一次请求队列,如果条件为真,则setResult

同步版本会是这样的

@RequestMapping(value = "/sync")
public ModelAndView checkState() {
if (null == SecurityHelper.getUserLogin()) {
createSuccessResponse("Invalidated session");
}
return null; // return something instead
}

但是一段时间后我遇到了一个异常(exception)

java.lang.IllegalStateException: Cannot forward after response has been committed
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:349) ~[tomcat-embed-core-7.0.
39.jar:7.0.39]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339) ~[tomcat-embed-core-7.0.39
.jar:7.0.39]
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:467) [tomcat-embed-core-7.0.39.jar:7.0.3
9]
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:338) [tomcat-embed-core-7.0.39.jar:7.0.3
9]
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:428) [tomcat-embed-core-7.0.39.jar:7.
0.39]
at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:417) [tomcat-embed-core-7.0.39.jar:
7.0.39]
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:294) [tomcat-embed-core-7.0.39.jar:7
.0.39]
at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1567) [tomcat-embed-c
ore-7.0.39.jar:7.0.39]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:583) [tomcat-embed-cor
e-7.0.39.jar:7.0.39]
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) [tomcat-embed-core-7.0.39.jar:7.
0.39]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_67]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_67]
at java.lang.Thread.run(Thread.java:745) [na:1.7.0_67]

有什么问题吗?我应该为 DeferredResult 设置超时吗?

最佳答案

我认为问题来自@ResponseBody注解。它告诉Spring Controller 方法将直接返回响应的主体。但事实并非如此,因为它返回 ModelAndView 。因此 Spring 尝试将方法的返回结果直接发送到客户端(并且应该发送并提交一个空响应),然后 ModelAndView 处理程序尝试转发到一个已提交响应的 View ,从而导致错误。

您至少应该删除 @ResponseBody注释,因为它不是同步等效项。

但这还不是全部:

  • 你写final DeferredResult<... - 恕我直言,最后一个不应该在那里,因为您稍后将修改 DeferredResult
  • 您尝试在计划的异步线程中测试登录的用户。这不应该起作用,因为常见的 SecurityHelper 使用本地线程存储来存储此信息,并且实际处理将在另一个线程中进行。 Javadoc DeferredResult甚至说:例如,人们可能希望通过扩展类并为用户添加附加属性来关联用于创建 DeferredResult 的用户。这样,用户以后就可以轻松访问,而不需要使用数据结构来进行映射。
  • 您没有说明如何配置异步支持。 Spring 引用手册说:MVC Java 配置和 MVC 命名空间都提供了用于配置异步请求处理的选项。 WebMvcConfigurer有方法 configureAsyncSupport<mvc:annotation-driven>有一个 <async-support>子元素。

关于java - 使用 deferredResult 时,无法在提交响应后转发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31515431/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com