jQuery Ajax GET请求执行两次

17

我有如下ajax请求,它在按钮点击时被执行:

<a href="javascript:test()"><img src="css/images/test.png"></a>

function test(){
    console.debug("*");

    $.ajax({
        type: "GET",
        dataType: "json",
        url: '/path/to/url',
        success: function(data){
            console.debug("**");
        }, 
        error: function(jqXHR, status, error){
            console.debug("*** " + status + " : " + error + " : " + jqXHR.status);
        },
        cache: false
    });
}

请求响应大约需要30秒才能返回。然而,服务器接收和执行请求两次,这可以从apache日志中看到。请求的时间戳相隔30秒,但请求是相同的(例如?_=1363692320782)。单击响应函数被调用一次,错误回调在初始请求后60秒被调用,尽管Apache响应是200。

这个问题已经在三星Galaxy S2上的Android版本2.3.5中的phonegap应用程序中复现。

更新-添加来自下面评论的Apache日志条目

1.2.3.4 - - [19/Mar/2013:14:07:59 +0000] "GET /pcapi/records/dropbox/08342hjg9gpqm7g/?_=1363702072225 HTTP/1.1" 200 11139 "-" "Mozilla/5.0 (Linux; U; Android 2.3.5; en-gb; GT-I9100 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"
1.2.3.4 - - [19/Mar/2013:14:08:29 +0000] "GET /pcapi/records/dropbox/08342hjg9gpqm7g/?_=1363702072225 HTTP/1.1" 200 11139 "-" "Mozilla/5.0 (Linux; U; Android 2.3.5; en-gb; GT-I9100 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"

更新 - adb logcat

I/Web Console(16747): * at file:///android_asset/www/js/mobile.js:1769
I/Web Console(16747): *** error : : 0 at file:///android_asset/www/js/mobile.js:1779

更新 - TCP/IP 监视器

通过 TCP/IP 监视器发送请求,显示两个请求都发送成功,并且都得到了200的响应。


@Gajotres 在桌面浏览器中不会出现这种情况,当在 weire 中运行时,您只会看到一个请求。 - gmh04
你觉得你能否猜测一下并增加或减少服务器返回所需的时间,使其显著地长于或短于30秒?我很好奇你是否仍会看到你正在获取的30秒超时。我之所以问这个问题是因为30秒是各种事物的相当常见的默认超时值... - Matt Gibson
@MattGibson 当服务器调用时间少于30秒时,只会进行一次调用并返回成功,如果响应时间大于30秒,则重新发送请求,ajax调用将返回错误。 - gmh04
1
你能展示一下注册按钮“click”事件处理程序的代码吗?你确定在PhoneGap上没有注册两次吗? - Vlad Stirbu
@gmh04 嗯,那种情况下我会尝试Carlos的答案,并设置一个较高的超时时间。不过这取决于你似乎看到的超时级别是什么。 - Matt Gibson
显示剩余4条评论
9个回答

6
如果您在此处定义的URL路径url:'/path/to/url'是文件夹而不是特定的文件,请尝试添加斜杠标记,例如url:'/path/to/url/'
如果未指定文件,则Apache Web服务器将使用新的URL(带有斜杠标记)向AJAX客户端发送301重定向,因此客户端会向正确的URL发出新请求。
请参见类似问题的发布:jQuery $.ajax() executed twice? 请参见Apache文档链接:http://httpd.apache.org/docs/2.0/mod/mod_dir.html#directoryslash

1
是的,我知道。我的意思是你的URL是否包含文件名?例如,你的URL是 www.domain.com/folder/index.php 还是 www.domain.com/folder/ ?如果不包括文件名,则尝试在URL末尾添加斜线。 - Miguel-F
你在发布的这两个请求周围没有看到其他日志条目吗?能否在这两个请求周围再发布一些Apache日志? - Miguel-F
你有没有任何未共享的全局 ajax 设置,使用 $.ajaxSetup() - Miguel-F
我已经在上面发布了adb logcat,我不使用$.ajaxSetup()。 - gmh04
我希望你能够发布更多来自你的Web服务器日志(来自Apache服务器)的内容。你能分享一下在这2个请求发出时的Web服务器日志条目吗(不仅仅是这两个条目)? - Miguel-F
显示剩余10条评论

6
我在运行Android 2.3.5的应用程序中遇到了这个问题。我只能得出结论,即webview在超时后会重试请求。我找不到任何方法来影响超时的持续时间。
最后,我重写了代码,使初始请求在服务器上启动异步进程并立即返回。然后,在页面上设置定时器,我将检查服务器进程的状态(同样立即返回)。当状态为“完成”时,页面将继续进行下一步。
希望这有所帮助。我完全理解你对此的沮丧。我自己也花了几天时间与之斗争。
编辑:这可能是引导我走向异步解决方案的文章。我相信这里所述的问题是一致的:
XmlHttpRequest在Android中双重发布问题

是的,目前“解决方案”是避免30秒的响应时间。可以采用你所描述的方法或类似的方法,或者重新设计服务器端应用程序来实现。 - gmh04

3

使用 beforeSend:complete: 以及 .ajaxSend() + ajaxSuccess(),同时尝试使用 cache: true

$(document).ajaxSend(function (event, jqxhr, settings) {
    console.log("triggered ajaxSend !");

    if ( submission_active == true ) {
        jqxhr.abort();
    }

    submission_active = true;
});

$(document).ajaxSuccess(function (event, xhr, settings) {
    console.log("triggered ajaxSuccess !");
    submission_active = false;
});

$.ajax({
    type: "GET",
    dataType: "json",
    timeout: 30000,
    cache: false,
    url: '/path/to/url',
    success: function(data){
        console.debug("**");
    }, 
    beforeSend: function(xhr, opts){
        if(submission_active == true){
            xhr.abort();
        }

        submission_active = true;
    },
    complete: function(){
        submission_active = false;
    }
    error: function(jqXHR, status, error){
        console.debug("*** " + status + " : " + error);
    }
});

如果超时时间小于响应时间,我会得到一个超时和一个请求。如果超时时间大于响应时间但小于响应时间的两倍,我会得到一个超时和两个请求。如果超时时间大于响应时间的两倍,我会得到一个错误和两个请求。 - gmh04
注意:在第三种情况下,错误恰好发生在初始请求后60秒。 - gmh04
虽然与此不太相关,但我建议您在任何情况下都要检查从/path/to/url脚本获取的JSON响应是否为有效的JSON,因为空响应不被视为有效响应,可能会引发错误或产生不可预测的结果。至少请确保您发送了一个空(但有效)的JSON,例如null或{}(在PHP中返回json_encode = array();即可)。 - Carlos Castillo
如果响应时间少于30秒,则一切正常。哦,而且我已经对所有其他设备进行了测试,只有三星Galaxy S2出现故障。 - gmh04
添加了.ajaxSend()ajaxSuccess(),试试看...如果这不起作用,我真的不知道还有什么可以尝试的了。 - Carlos Castillo
显示剩余2条评论

2
我曾在移动网站开发中尝试过这种方法,唯一的问题出现在我的表单上,然后在我的JavaScript中声明了。
$("#button_submit").onclick(function(){
   //ajax request here
});

同时,如果您正在使用ajax,请不要忘记删除表单属性,例如操作和方法。

希望这可以帮助到您 ^_^


2

单击事件被触发两次。以下代码可以解决此问题。

$('.selector').unbind('click').bind('click', function () {
 //...
 // Ajax code
 //...
});

事件已经被触发一次。 - gmh04

1
 <a href="javascript:test()">

这是你的问题。如果你要使用jQuery,请使用它们的CSS选择器!那个href:javascript的东西在不同的浏览器/设备上会出现错误。


1
听起来更像是事件传播的问题。我曾经遇到过类似的症状(尽管在iOS上),最终发现是“touchstart”和“touchend”事件都触发了“click”事件。你是否尝试过像这样的解决方法:
$("a").click(function (e) {
    e.preventDefault();
    alert('Clicked');
    test();
});

希望这有所帮助!
祝好
JD

0

我遇到了同样的问题,我在提交按钮上绑定了点击事件,结果ajax运行了两次。 与其绑定事件,我使用了以下代码中的onClick方法:

<button onclick"myProcess()"></button>

而且它解决了我的问题。


0
你面临的问题通常被称为"弹跳",电子开关也会遇到这种情况。当你按下并释放按钮时,开关会触发两次,因此你需要设置功能延迟或在点击完成后解除绑定。
你可以使用Ben Alman的节流脚本来去抖动你的点击,它非常有用,可以防止多个ajax调用同时发生,结合延迟使用,你的问题应该会得到解决。

http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/

            var debounceClick = $.debounce(test, 1000);
            function test() {
                console.debug("*");
                $.ajax({
                    type: "GET",
                    dataType: "json",
                    url: '/path/to/url',
                    success: function(data){
                        console.debug("**");
                    }, 
                    error: function(jqXHR, status, error){
                        console.debug("*** " + status + " : " + error + " : " + jqXHR.status);
                    },
                    cache: false
                });
            }

现在从链接中调用debounceClick函数以解决您的问题。

或者,您也可以使用简单的纯JavaScript而不是节流插件来实现您的结果:

            var timeout;
            function test(){
                console.debug("*");
                $.ajax({
                    type: "GET",
                    dataType: "json",
                    url: '/path/to/url',
                    success: function(data){
                        console.debug("**");
                    }, 
                    error: function(jqXHR, status, error){
                        console.debug("*** " + status + " : " + error + " : " + jqXHR.status);
                    },
                    cache: false
                });
            }

            function click() {
                if(timeout) {
                         clearTimeout(timeout);
                }
                timeout = setTimeout(test, 1000);
            }

在这个例子中,将click()函数绑定到您的链接。

但是事件只触发一次。 - gmh04

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接