我正在尝试在我的 Spring-MVC Web 应用程序中实现长轮询,但在 4-5 继续 AJAX 请求后冻结了我的浏览器和其他请求。我不知道这是我的相关代码。
控制器方法:(服务器端):-
@Asynchronous
@RequestMapping("/notify")
public @ResponseBody
Events notifyEvent(HttpServletRequest request) {
Events events = null;
try {
events = (Events) request.getSession(false).getServletContext().getAttribute("events");
System.out.println("Request Came from" + ((com.hcdc.coedp.safe.domain.User) request.getSession(false).getAttribute(Constants.KEY_LOGGED_IN_USER)).getLoginId());
if (!events.getTypeOfEvents().isEmpty()) {
System.out.println("Removing older entries");
events.getTypeOfEvents().clear();
}
while (!events.isHappend()) {
//Waiting for event to happen.
}
events = Events.getInstance();
events.setHappend(false);
request.getSession(false).getServletContext().setAttribute("events", events);
}catch (Exception e) {
e.printStackTrace();
}
return events;
}
长轮询脚本(客户端):-
$(document).ready(function() {
$.ajaxSetup({
async:true//set a global ajax requests as asynchronus
});
alert('Handler for .onload() called.');
waitForMsg();
});
function waitForMsg(){
xhr= $.ajax({
type: "POST",
url: '<%=request.getContextPath()%>/notification/notify',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
global:false,
success: function(data){ /* called when request to notifier completes */
/* Doing smthing with response **/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
更新:
function updateFeed(event, data) {
var f=eval(data);
alert(f.typeOfEvents.length);
}
function catchAll(event, data, type) {
console.log(data);
alert("error");
console.log(type);
}
$.comet.connect('<%=request.getContextPath()%>/notification/notify');
$(document).bind('feed.comet', updateFeed);
$(document).bind('.comet', catchAll);
两个警报框都没有弹出..:(
似乎您遇到了会话文件锁定
对于 PHP
在不需要会话值时使用session_write_close()
浏览器代码中似乎有一个空的while循环..这是等待事件的一种非常占用CPU的方式。
如果没有发生任何事件,客户端将在所需的 50 秒超时后终止请求。但我不确定服务器线程是否也被杀死,或者它是否永远"同时"打开(除非有事件)。下一个请求将启动第二个服务器线程,该线程也会在 while 循环中挂起。也许空 while 循环的数量对服务器来说是一种矫枉过正,因此它停止接受任何更多的请求。因此,在某些请求(每个请求触发了无休止的服务器线程)之后,客户端将永远等待新请求。因为它不能由服务器处理。
PS:成功后,您评论等待1秒,但将超时设置为10000(10秒)
我遇到了类似的问题,我的浏览器不知何故被 AJAX 请求卡住了。提示:直接使用 waitForMsg() 代替,请尝试 setTimeout("waitForMsg()",10)。
仅供参考,这里有一个可能对你有帮助的项目:https://github.com/SeanOC/jquery.comet
一般来说,我会搜索可以支持 Web 套接字的 JavaScript 彗星 API,如果在客户端/服务器上可用,并且可以优雅地回退到长轮询。API 应该处理所有血腥的细节,让你专注于应用程序。
这是关于该主题的旧道场文章的链接:http://dojotoolkit.org/features/1.6/dojo-websocket
祝你好运。
您可以尝试使用 jQuery 延迟重写行为:
function setShortTimeout() {
setTimeout(waitForMsg, 1000);
}
function setLongTimeout() {
setTimeout(waitForMsg, 15000);
}
$(document).ready(function() {
$.ajaxSetup({
async:true//set a global ajax requests as asynchronus
});
alert('Handler for .onload() called.');
$.when(waitForMsg())
.done(successHandler, setShortTimeout)
.fail(errorHandler, setLongTimeout);
});
function waitForMsg(){
return $.ajax({
type: "POST",
url: '<%=request.getContextPath()%>/notification/notify',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
global:false
});
};
errorHandler
和successHandler
将是你的成功:和错误:回调,为了清楚起见,我省略了回调,删除了它们的setTimeout部分(因为它现在是deferred.done()和.fail()回调的一部分)。
让我知道它是否有效。
我是一名PHP开发人员,但我遇到了你的问题,这可能是相同的行为。所以我给你我的2美分,希望它能帮助你。
让我怀疑有问题的行是:
events = (Events) request.getSession(false).getServletContext().getAttribute("events");
在 PHP 中,会话存储在文件中,如果我们在会话打开时对 php 脚本进行长时间轮询,则会遇到竞争条件问题。
原理很简单:
- 当请求打开会话时,文件将被锁定,直到会话已关闭。
- 如果其他请求进入服务器,它们将被锁定,直到会话从上一个请求中释放。
在长轮询的情况下,如果会话在获取信息后打开而不是关闭(至少,就在等待事件之前),则所有请求都被锁定,如果您在其他页面上使用会话,则无法转到网站中的其他任何地方。即使您打开一个新选项卡,因为对于一个浏览器只有一个会话,您也被锁定了。
这样的:
xhr= $.ajax({ (...)
在您的等待消息函数中。
尝试
var xhr = (...)
可能是您在全局对象中声明了 xhr,因此无法响应两个不同的请求。