浏览器关闭时Servlet长时间处理取消

时间:2009-02-06 13:51:29

标签: java http servlets java-ee browser

我有一个servlet,它长时间处理请求。它假设 继续在doPost内部循环中执行操作并发送数据 响应出来的作家。有效地连续追加数据 客户浏览器。 但是当客户端关闭浏览器时问题就会出现问题。尽管 断开的连接响应的servlet中的编写器流 永远不会关闭,因此servlet不知道brocen连接, 并保持数据转储到编写器没有任何错误。那个怎么样 posssible?我如何检测和取消长请求处理 浏览器断开的情况?

我想知道响应编写器上的checkError()应该做的伎俩,但它没有缝合工作。有什么想法吗?

这是永远不会停止的servlet代码:

protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
   HttpSession session = request.getSession();
   System.out.println("Session " + session.getId() + " started");

   response.setContentType("text/html;charset=UTF-8");

   PrintWriter out = response.getWriter();
   try
   {
       while (!out.checkError())
       {
           try
           {
               Thread.sleep(1000);
           } catch (InterruptedException ex)
           {
               ex.printStackTrace();
           }

           Date date = new Date();

           // TODO append output to the client browser here
           out.println(".....");

           System.out.println("Session " + session.getId() + "data sent at: " + date);

           out.flush();
       //break;  // _TEST
       }
   } finally
   {
       System.out.println("Session " + session.getId() + " finished");
       out.close();
   }
}

谢谢,
麦克

6 个答案:

答案 0 :(得分:4)

解决这个问题的唯一真正方法是让浏览器不断告诉你它仍然在那里,比如说每5-10秒。如果你在没有听到任何声音的情况下匆匆走了一会儿,你就会认为客户已经走了,忘了你在做什么。

有几种方法可以实现这一点:

  • 元刷新:我不喜欢这个,因为它对用户来说是令人不安和明显的;
  • 执行此操作的iframe(不太明显);或
  • 一些AJAX技术,这可能是最好的选择。

没有真正的方法可以检测客户端是否仍在阅读您发送的内容。 TCP连接死亡需要时间,而客户端的路径通常是间接的(通过代理等等),所以忘记检测它。

答案 1 :(得分:1)

servlet有一个输出缓冲区,必须在数据实际发送到浏览器之前填满。如果此缓冲区尚未填充,则实际上不会在网络上发送任何数据。在您通过网络发送数据之前,您不会知道连接已关闭。

您可以通过在获取输出流或编写器之前调用响应对象上的方法来设置缓冲区大小。

答案 2 :(得分:1)

您正在尝试执行HTTP协议不支持的操作。 Web的整体性质基于请求/响应。

模拟您需要的一种方法是使用Ajax。 流程将是这样的:

  1. 浏览器使用Ajax发送项目1到10的请求
  2. 服务器处理请求,构建和发送包含1到10项的响应。
  3. 浏览器接收响应,解析结果,显示1到10的项目并重复步骤1,请求项目11到20.
  4. 这种架构不需要检查客户端的“可用性”,也可以提高服务器端组件的可扩展性。

    我希望它有所帮助。

答案 3 :(得分:0)

java.io.PrintWriter javadoc sez:此类中的方法永远不会抛出I / O异常 - 所以请改用javax.servlet.SocketOutputStream(response.getOutputStream()),最终会得到一些IOException。

答案 4 :(得分:0)

您的一般方法对我有用(我有一个长期运行的服务器任务,如果客户端挂起,使用checkError,在一些合理的卷无法发送后,就可以中止了)。我可以建议您更新到最新的Java版本。

答案 5 :(得分:0)

我们遇到了类似的问题。在我们的例子中,是启用了ESI的网络服务器(http://www-01.ibm.com/support/docview.wss?uid=swg27015501)。我们做了一个TCP转储,看看那里发生了什么,看到RES包(浏览器关闭后)从未发送回应用程序。网络服务器收到了它,但没有进一步发送。因此,printer.checkError()从未返回true并且打印机保持刷新数据。 禁用此功能后,RES包被发送到应用程序,一段时间后,printer.checkError()返回true。 这就是我偶然发现你的问题的原因。它不断发送3次。之后,checkError()返回true。