Servlet 3.0:无法发送异步响应?
Posted
技术标签:
【中文标题】Servlet 3.0:无法发送异步响应?【英文标题】:Servlet 3.0: Can't send an asynchronous response? 【发布时间】:2011-05-10 21:00:56 【问题描述】:我无法为用户建立 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 的调试工具),服务器似乎在请求发送后大约 30000 毫秒发送了 HTTP 500 响应。
使用 userAsyncContext.getResponse().getWriter().print(SOME_JSON) 创建并在 HTTP 500 响应之前发送的任何响应都不会被浏览器接收,我不知道为什么。仅当处理 AsyncContext 的“if”语句中的所有代码都不存在时,浏览器才会接收使用常规响应对象发送响应 (response.print(SOME_JSON))。
有人可以帮帮我吗?我有一种感觉,这是由于我对异步 API 的工作原理有误解。我认为我可以将这些 AsyncContexts 存储在全局映射中,然后检索它们并使用它们的响应对象将内容推送给客户端。但是,似乎 AsyncContexts 不能写回客户端。
任何帮助都将不胜感激。
【问题讨论】:
【参考方案1】:我解决了这个问题。我的方法似乎有几个问题:
在 Glassfish 中,AsyncContext 对象的默认超时时间均为 30,000 毫秒(0.5 分钟)。一旦此期限到期,整个响应将提交回客户端,这意味着您将无法再次使用它。
如果您正在实现长轮询,这可能不是什么大问题(因为无论如何您最终都会在响应之后发送另一个请求),但是如果您希望实现流式传输(将数据发送回客户端不提交响应)你会想要增加超时,或者一起摆脱它。
这可以通过 AsyncContext 的 .setTimeout()
方法来完成。请注意,虽然spec 声明:“超时值为零或更小表示没有超时。”,Glassfish(此时)似乎将 0 解释为“需要立即响应”,任何负数都解释为“没有超时” ”。
如果您正在实现流式传输,则在使用 printwriter 的 .print()
.println()
或 .write()
方法写入数据后,必须使用 printwriter 的 .flush()
方法将数据推送到客户端。
在客户端,如果您已流式传输数据,它将触发 3 的 readyState(“交互式”,这意味着浏览器正在接收响应)。如果您使用 jQuery,则没有简单的方法来处理 3 的 readyStates,因此如果您正在实施流式传输,您将不得不恢复为常规 javascript 以便发送请求和处理响应。
【讨论】:
【参考方案2】:我注意到,在 Glassfish 中,如果您使用 AsyncContext 并将 .setTimeOut() 设置为负数,无论如何连接都会中断,要解决此问题,我必须使用 Glassfish 管理员网络配置器:asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-1.http。并将超时设置为-1。所有这些都是为了避免 glassfish 在 30 秒后完成连接。
【讨论】:
以上是关于Servlet 3.0:无法发送异步响应?的主要内容,如果未能解决你的问题,请参考以下文章
Servlet-3 Async Context,如何进行异步写入?