【问题标题】:Check client is alive with HttpServletRequest object检查客户端是否存在 HttpServletRequest 对象
【发布时间】:2015-01-27 00:57:20
【问题描述】:

我正在编写一个 Spring Web 应用程序,并将“/do” URL 路径映射到以下 Controller 的方法

@Controller
public class MyController
{
    @RequestMapping(value="/do",  method=RequestMethod.GET)
    public String do()
    {
        File f = new File("otherMethodEnded.tmp");
        while (!f.exists())
        {
            try {

                Thread.sleep(5000);

            } catch (InterruptedException e) {

            }
        }

        // ok, let's continue
    }
}

otherMethodEnded.tmp 文件是由另一个控制器的方法编写的,所以当客户端调用第二个 URL 时,我希望第一个方法退出 while 循环。

一切正常,除非客户端调用“/do” URL,然后在收到响应之前关闭连接。问题是即使客户端已关闭,服务器仍处于while (!f.exists()) 循环中,并且无法调用第二个 URL 来解锁 while 循环。

我会尝试检索“/do” URL 的连接状态并在客户端关闭连接时退出循环,但我找不到任何方法。

我尝试了HttpServletRequest.getSession(false)方法,但是返回的HttpSession对象总是不为空,所以HttpServletRequest对象在客户端连接关闭的情况下不会更新。

如何检查客户端是否仍在等待响应?

【问题讨论】:

    标签: java spring http servlets model-view-controller


    【解决方案1】:

    验证某事不正确的最简单方法是定义一个超时值,然后在循环测试期间,如果您花费的等待时间超过了超时。

    类似:

    @Controller
    public class MyController
    {
        private static final long MAX_LOOP_TIME = 1000 * 60 * 5; // 5 minutes? choose a value
    
        @RequestMapping(value="/do",  method=RequestMethod.GET)
        public String do()
        {
            File f = new File("otherMethodEnded.tmp");
            long startedAt = System.currentTimeMillis()
            boolean forcedExit = false;
            while (!forcedExit && !f.exists())
            {
                try {
                    Thread.sleep(5000);
                    if (System.currentTimeMillis() - startedAt > MAX_LOOP_TIME) {
                        forcedExit = true;
                    }
                } catch (InterruptedException e) {
                    forcedExit = true;
                }
            }
    
            // ok, let's continue
    
            // if forcedExit , handle error scenario?
        }
    }
    

    另外:InterruptedException 不是盲目捕捉和忽略的东西。见this discussion

    如果你被打断,我真的会退出 while 循环。

    只有当您注意到您写入的输出流 (response.outputstream) 已关闭时,您才知道客户端是否不再等待您的连接。但是没有办法检测它。 (详见this question

    鉴于您已表明您的客户偶尔会进行回调,您可以在客户端轮询其他呼叫是否已完成。如果此其他调用已完成,则执行该操作,否则直接返回并让客户端再次执行该调用。 (假设您正在发送 json,但根据需要进行调整)

    类似

    public class MyController
    {
        @RequestMapping(value="/do",  method=RequestMethod.GET)
        public String do()
        {
            File f = new File("otherMethodEnded.tmp");
            if (f.exists()) {
                // do what you set out to do
                // ok, let's continue
    
    
                // and return with a response that indicates the call did what it did
                // view that returns json { "result" : "success" } 
                return "viewThatSIgnalsToClientThatOperationSucceeded";
            } else {
                // view that returns json:  { "result" : "retry" }
                return "viewThatSignalsToClientToRetryIn5Seconds"; 
            }
        }
    }
    

    然后客户端会运行类似:(伪javascript,因为它已经有一段时间了)

    val callinterval = setInterval(function() { checkServer() }, 5000);
    
    function checkServer() {
        $.ajax({
            // ...
            success: successFunction
        });
    }
    
    function successFunction(response) {
        // connection succeeded
        var json = $.parseJSON(response);
        if (json.result === "retry") {
            // interval will call this again
        } else {
            clearInterval(callinterval);
            if (json.result === "success") { 
                // do the good stuff
            } else if (json.result === "failure") {
                // report that the server reported an error
            }
        }
    }
    

    当然,这只是半严肃的代码,但如果我有依赖关系,这大致就是我尝试的方式。如果这是关于文件上传,请记住该文件可能尚未包含所有字节。文件存在!= 文件= 完全上传,除非您使用移动它。 cp / scp / etc. 不是原子的。

    【讨论】:

    • 感谢您的建议。您回答中的唯一问题是我不知道客户端何时会调用第二个 URL,因此我无法为循环定义正确的超时,因为我会危及操作。 +1 关于 InterruptedException 的好处
    • 我现在使用的解决方案是让客户端定期轮询服务器。这样服务器就知道客户端是否在线,是否应该继续循环
    • 可能你不想用while循环无限期地捆绑客户端。如果客户已经回电,那么我将用替代方法更新我的答案
    猜你喜欢
    • 2013-01-16
    • 1970-01-01
    • 2015-02-19
    • 2016-05-19
    • 1970-01-01
    • 2011-09-20
    • 2012-07-27
    • 1970-01-01
    • 2015-05-02
    相关资源
    最近更新 更多