Servlet 3.0:无法发送异步响应?

时间:2011-05-10 21:00:56

标签: java asynchronous java-ee comet servlet-3.0

我无法为用户建立AsyncContexts并使用它们向他们推送通知。在页面加载时,我有一些jQuery代码来发送请求:

$.post("TestServlet",{
    action: "registerAsynchronousContext"
        },function(data, textStatus, jqXHR){
            alert("Server received async request"); //Placed here for debugging   
  }, "json");

在“TestServlet”中,我在doPost方法中有这个代码:

HttpSession userSession = request.getSession();
String userIDString = userSession.getAttribute("id").toString();

String paramAction = request.getParameter("action");

if(paramAction.equals("registerAsynchronousContext"))
{              
    AsyncContext userAsyncContext = request.startAsync();

    HashMap<String, AsyncContext> userAsynchronousContextHashMap = (HashMap<String, AsyncContext>)getServletContext().getAttribute("userAsynchronousContextHashMap");
    userAsynchronousContextHashMap.put(userIDString, userAsyncContext);
    getServletContext().setAttribute("userAsynchronousContextHashMap", userAsynchronousContextHashMap);

    System.out.println("Put asynchronous request in global map");
}

    //userAsynchronousContextHashMap is created by a ContextListener on the start of the web-app

然而,根据Opera Dragonfly(像Firebug这样的调试工具),服务器在发送请求后大约30000ms会发送HTTP 500响应。

使用userAsyncContext.getResponse()。getWriter()。print(SOME_JSON)创建的任何响应,并在浏览器未收到HTTP 500响应之前发送,我不知道为什么。只有当处理AsyncContext的“if”语句中的所有代码都不存在时,浏览器才会使用常规响应对象发送响应(response.print(SOME_JSON))。

有人可以帮帮我吗?我有一种感觉,这是因为我误解了异步API的工作原理。我认为我可以将这些AsyncContexts存储在全局映射中,然后检索它们并使用它们的响应对象将内容推送到客户端。但是,似乎AsyncContexts不能回写给客户端。

任何帮助都会被贬低。

2 个答案:

答案 0 :(得分:5)

我解决了这个问题。似乎我的方法有几个问题是错误的:

  1. 在Glassfish中,AsyncContext对象的默认超时时间均为30,000毫秒(.5分钟)。一旦此期限到期,整个回复将被提交给客户,这意味着您将无法再次使用它。

    如果您正在实施长轮询,这可能不是什么大问题(因为您最终会在响应之后发送另一个请求),但是如果您希望实现流式传输(将数据发送回客户端)如果没有提交响应,你会想要增加超时,或者一起消除它。 这可以使用AsyncContext的.setTimeout()方法完成。请注意,虽然spec状态:“超时值为零或更少表示没有超时。”,Glassfish(此时)似乎将0解释为“需要立即响应”,并将任何负数解释为“没有超时“。

  2. 如果您正在实施流式传输,则必须使用printwriter的.flush()方法将数据推送到客户端后,使用其.print() .println()或{ {1}}写入数据的方法。

  3. 在客户端,如果您已对数据进行流式传输,则会触发readyState为3(“交互式”,这意味着浏览器正在接收响应)。如果您使用的是jQuery,则没有简单的方法来处理3的readyStates,因此如果您正在实现流式传输,那么您将不得不恢复为常规Javascript以发送请求并处理响应。

答案 1 :(得分:2)

我注意到在Glassfish中如果使用AsyncContext并使用.setTimeOut()为负数,则无论如何连接都会被破坏,为了解决这个问题,我必须去我的Glassfish管理员Web配置器:asadmin set configs.config.server-config.network-config.protocols.protocol.http侦听器1.http。并将超时设置为-1。这一切都是为了避免玻璃鱼在30秒后完成连接。