使用HttpServletRequest对象检查客户端是否处于活动状态

时间:2014-11-28 11:09:46

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

我正在编写一个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文件是由另一个Controller的方法写的,所以当客户端调用第二个URL时,我希望第一个方法退出while循环。

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

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

我尝试使用HttpServletRequest.getSession(false)方法,但返回的HttpSession对象始终不为空,因此在客户端连接关闭的情况下,HttpServletRequest对象不会更新。

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

1 个答案:

答案 0 :(得分: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 /等不是原子的。