CAS No flow execution could be found with key 'e2s1' 问题

发布于 2022-09-04 10:45:43 字数 8901 浏览 26 评论 0

在使用jasig-cas构建的单点登录系统中,遇到一个错误,表象是提交登录表单时,前端表现为刷新一次页面,实际是后端提交POST请求时,发生了一个错误:

org.springframework.webflow.execution.repository.NoSuchFlowExecutionException: No flow execution could be found with key 'e2s1' -- perhaps this executing flow has ended or expired? This could happen if your users are relying on browser history (typically via the back button) that references ended flows.
    at org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:172)
    at org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getLock(AbstractFlowExecutionRepository.java:125)
    at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:167)
    at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter2.handle(FlowHandlerAdapter2.java:186)
    at org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter2.handle(SelectiveFlowHandlerAdapter2.java:69)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:933)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:867)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:855)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.jasig.cas.web.init.SafeDispatcherServlet.service_aroundBody2(SafeDispatcherServlet.java:125)
    at org.jasig.cas.web.init.SafeDispatcherServlet.service_aroundBody3$advice(SafeDispatcherServlet.java:54)
    at org.jasig.cas.web.init.SafeDispatcherServlet.service(SafeDispatcherServlet.java:1)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1496)
    at org.jasig.cas.security.RequestParameterPolicyEnforcementFilter.doFilter(RequestParameterPolicyEnforcementFilter.java:296)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1484)
    at com.github.inspektr.common.web.ClientInfoThreadLocalFilter.doFilter(ClientInfoThreadLocalFilter.java:63)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1484)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1476)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:429)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:154)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
    at org.eclipse.jetty.server.Server.handle(Server.java:370)
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
    at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:982)
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1043)
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:865)
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.webflow.conversation.NoSuchConversationException: No conversation could be found with id '2' -- perhaps this conversation has ended? 
    at org.springframework.webflow.conversation.impl.ConversationContainer.getConversation(ConversationContainer.java:134)
    at org.springframework.webflow.conversation.impl.SessionBindingConversationManager.getConversation(SessionBindingConversationManager.java:116)
    at org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:183)
    at org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:170)
    ... 49 more

由于是偶然出现,时灵时不灵的,跟踪难度很大,通过研究相应代码:

// org.springframework.webflow.mvc.servlet.FlowHandlerAdapter

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    
    FlowHandler flowHandler = (FlowHandler) handler;
    checkAndPrepare(request, response, false);
    // 从请求参数中获取`execution`参数值
    String flowExecutionKey = flowUrlHandler.getFlowExecutionKey(request);
    if (flowExecutionKey != null) {
        try {
            ServletExternalContext context = createServletExternalContext(request, response);
            // 恢复`execution`值(NULL),报错点
            FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context);
            handleFlowExecutionResult(result, context, request, response, flowHandler);
        } catch (FlowException e) {
            e.printStackTrace();
            handleFlowException(e, request, response, flowHandler);
        }
    } else {
        try {
            String flowId = getFlowId(flowHandler, request);
            MutableAttributeMap input = getInputMap(flowHandler, request);
            ServletExternalContext context = createServletExternalContext(request, response);
            // 创建execution[e1s1]
            FlowExecutionResult result = flowExecutor.launchExecution(flowId, input, context);
            handleFlowExecutionResult(result, context, request, response, flowHandler);
        } catch (FlowException e) {
            handleFlowException(e, request, response, flowHandler);
        }
    }
    return null;
}

跟踪内部代码找到相应代码

// org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository

public FlowExecutionResult resumeExecution(String flowExecutionKey, ExternalContext context) throws FlowException {
    try {
        if (logger.isDebugEnabled()) {
            logger.debug("Resuming flow execution with key '" + flowExecutionKey);
        }
        ExternalContextHolder.setExternalContext(context);
        FlowExecutionKey key = executionRepository.parseFlowExecutionKey(flowExecutionKey);
        // 问题点,这里涉及到`Conversation`生命周期(个人感觉巨复杂,没能继续深入了)
        FlowExecutionLock lock = executionRepository.getLock(key);
        lock.lock();
        try {
            FlowExecution flowExecution = executionRepository.getFlowExecution(key);
            flowExecution.resume(context);
            if (!flowExecution.hasEnded()) {
                executionRepository.putFlowExecution(flowExecution);
                return createPausedResult(flowExecution);
            } else {
                executionRepository.removeFlowExecution(flowExecution);
                return createEndResult(flowExecution);
            }
        } finally {
            lock.unlock();
        }
    } finally {
        ExternalContextHolder.setExternalContext(null);
    }
}

涉及到Conversation生命周期(个人感觉巨复杂,没能继续深入了),这里偷个懒,发贴请教一下有经验的小伙伴们 ~

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文