8

我正在尝试在我的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);

两个警报框都不会弹出..:(

4

7 回答 7

10

好像您遇到了会话文件锁定

对于 PHP

session_write_close()在不需要会话值时使用

于 2013-12-14T06:58:05.127 回答
5

您的浏览器代码中似乎有一个空的 while 循环。这是一种等待事件的 CPU 密集型方式。

如果没有事件发生,客户端将在您期望的 50 秒超时后终止请求。但我不确定服务器线程是否也被杀死,或者它是否永远“在”上(除非有事件)。下一个请求将启动第二个服务器线程,该线程也挂在 while 循环中。也许空的while循环的数量对服务器来说是一种过度杀伤,因此它停止接受更多的请求。所以在一些请求之后(每个请求都触发了一个无限的服务器线程),客户端永远等待一个新的请求......因为它不能被服务器处理。

ps:成功时您评论等待 1 秒,但将超时设置为 10000(10 秒)

于 2012-10-13T12:42:35.167 回答
2

我遇到了类似的问题,我的浏览器被 AJAX 请求卡住了。提示:而不是直接使用waitForMsg(),尝试setTimeout("waitForMsg()",10)

于 2012-10-12T09:26:54.337 回答
2

仅供参考,这是一个可能对您有所帮助的项目:https ://github.com/SeanOC/jquery.comet

一般来说,我会搜索可以支持 Web 套接字的 JavaScript comet API,如果在客户端/服务器上可用,并且可以优雅地回退到长轮询。API 应该处理所有血淋淋的细节,让您专注于应用程序。

这是关于该主题的旧 dojo 文章的链接:http: //dojotoolkit.org/features/1.6/dojo-websocket

祝你好运。

于 2012-10-12T19:14:39.970 回答
2

您可以尝试使用 jQuery deferred 重写行为:

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() 回调的一部分)。

让我知道它是否有效。

于 2012-10-18T11:02:46.013 回答
2

我是一名 PHP 开发人员,但我遇到了你的问题,它可能是相同的行为。所以我给你我的 2 美分,希望它会帮助你。

确实让我怀疑有问题的行是:

events = (Events) request.getSession(false).getServletContext().getAttribute("events");

在 PHP 中,会话存储在文件中,如果我们在会话打开时对 php 脚本进行长轮询,我们会遇到竞争条件问题。

原理很简单:

  1. 当请求打开会话时,文件将被锁定,直到会话关闭。
  2. 如果其他请求到达服务器,它们将被锁定,直到会话从前一个请求中释放。

在长轮询的情况下,如果会话在获取信息后打开而不是关闭(至少在等待事件之前),所有请求都被锁定,如果你是在其他页面上使用会话。即使您打开一个新选项卡,因为对于一个浏览器只有一个会话,您也会被锁定。

于 2012-10-18T22:04:02.883 回答
1

可能是这样的:

        xhr=  $.ajax({ (...)

在您的 waitForMsg 函数中。

尝试

    var xhr = (...)

可能是您在全局对象中声明了 xhr,因此无法响应两个不同的请求。

于 2012-10-18T09:10:36.150 回答