17

I have the following ajax request that is executed at a click of a button:

<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
    });
}

The request response takes approximately 30 seconds to return. However, the request is received and executed by the server twice as can be seen by the apache logs. The timestamp of the requests are 30 seconds apart but the request is identical (e.g ?_=1363692320782). The click response function is called once and the error callback is invoked once (exactly 60 seconds after initial request), although the apache response is a 200.

This problem has been reproduced in a Samsung Galaxy S2, android version 2.3.5 in a phonegap application.

UPDATE - adding Apache log entries from comment below

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"

UPDATE - 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

UPDATE - TCP/IP monitor

Putting the requests through a TCP/IP monitor shows both requests being sent with a 200 response for both.

gmh04
  • 1,351
  • 9
  • 24
  • What about browser logs, how many requests occurred? – Gajotres Mar 19 '13 at 12:37
  • @Gajotres This doesn't happen in a desktop browser, when run within weire you see only a single request. – gmh04 Mar 19 '13 at 13:29
  • How easy would it be for you to humour a guess of mine and increase or decrease the time it takes the server to return to significantly longer or shorter than 30 seconds? I'm curious as to whether you'd still see the 30-second timeout you're getting. I ask because 30 seconds is a fairly common default timeout value for various things... – Matt Gibson Mar 21 '13 at 13:15
  • @MattGibson When the server call is less that 30 seconds the call is only made once and a sucess is returned, if the response is greater than 30 seconds the request is resent and the ajax call returns an error. – gmh04 Mar 21 '13 at 14:27
  • 1
    can you show the code where you register the "click" event handler for the button? are you sure you don't register it twice on phonegap? – Vlad Stirbu Mar 21 '13 at 20:27
  • @gmh04 Hrm. In that case I'd try Carlos's answer next, and set a high timeout. Depends on what level the timeout you seem to be seeing is happening, though. – Matt Gibson Mar 21 '13 at 22:04
  • @VladStirbu ok done. yes I'm sure the event handler is registered only once. – gmh04 Mar 22 '13 at 10:44
  • @MattGibson See comment on Carlos's answer. – gmh04 Mar 22 '13 at 10:45
  • Things to consider when using jQuery mobile with PhoneGap and Android - [Building PhoneGap (Cordova) apps with jQuery Mobile](http://jquerymobile.com/demos/1.2.0/docs/pages/phonegap.html) – Miguel-F Mar 22 '13 at 14:17

9 Answers9

6

If your URL path defined here url: '/path/to/url' is to a folder and not a specific file try adding a trailing slash like this url: '/path/to/url/'.

What happens when a file is not specified is that the Apache web server sends a 301 redirect to the AJAX client with a new URL (with the trailing slash), so the client issues a new request to the proper URL.

See a similar question posted here: jQuery $.ajax() executed twice?

See the Apache doc reference here: http://httpd.apache.org/docs/2.0/mod/mod_dir.html#directoryslash

Community
  • 1
  • 1
Miguel-F
  • 13,450
  • 6
  • 38
  • 63
  • The URL is our server side application, not a directory. – gmh04 Mar 19 '13 at 13:33
  • 1
    Yes, I know. What I mean is does your URL contain the file name? For example, is your URL `www.domain.com/folder/index.php` or `www.domain.com/folder/` ? If it does not include the file name then try appending a trailing slash to the URL. – Miguel-F Mar 19 '13 at 13:37
  • Can you post the entries from your Apache logs showing the two requests? – Miguel-F Mar 19 '13 at 13:56
  • 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" – gmh04 Mar 19 '13 at 14:09
  • 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" – gmh04 Mar 19 '13 at 14:10
  • @gmh04 In your example code you have this line `console.debug("*");` within your `function test()` before the `ajax` call. How many times are you getting that console message? – Miguel-F Mar 22 '13 at 14:04
  • And you don't see any other log entries around the two requests that you posted? Could you post more from your Apache logs around the two requests? – Miguel-F Mar 22 '13 at 14:33
  • Do you have any global ajax settings that you have not shared, using `$.ajaxSetup()`? – Miguel-F Mar 22 '13 at 14:52
  • I've posted by adb logcat above, I don't use $.ajaxSetup() – gmh04 Mar 22 '13 at 15:12
  • I was hoping you could post more from your web server logs (from Apache server). Can you share the web server log entries around when the 2 requests are made (more than just those 2 entries)? – Miguel-F Mar 22 '13 at 15:36
  • Okay. Hmm? Then what about your success message `console.debug("**");`? All I see is the error message. I would expect two of the success messages. – Miguel-F Mar 22 '13 at 15:43
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/26740/discussion-between-gmh04-and-miguel-f) – gmh04 Mar 22 '13 at 15:55
  • Since your `XHR.status = 0` see the answer to this post http://stackoverflow.com/questions/8924482/phonegap-jquery-ajax-request-does-not-work which then suggests this http://simonmacdonald.blogspot.com/2011/12/on-third-day-of-phonegapping-getting.html which basically treats the status of 0 like a 200. – Miguel-F Mar 23 '13 at 01:31
  • Are you still getting 2 requests? Both requests have no data? Or are you saying the error callback has no data argument? If the latter, I believe that is why the other post I referred you to actually goes away from using the jQuery AJAX call and uses javascript's `XMLHttpRequest()` directly. – Miguel-F Mar 25 '13 at 12:08
  • Using XMLHttpRequest does not fix the problem. Two requests are still sent, status code 0 is returned (after 60 secs yet the request has not completed) and an empty responseText. – gmh04 Mar 25 '13 at 14:10
6

I hit this exact problem with my app running on Android 2.3.5. I could only conclude that the webview was retrying the request after a timeout. I could find no way to affect the duration of the timeout.

In the end, I rewrote the code such that the initial request spun off an asynch process on the server and returned immediately. Then, from a setTimer on the page, I would check the status of the server process (again, returning immediately). When the status was "complete", the page would move along to the next step.

I hope that helps. I certainly understand your frustration with this. I spent a couple of days myself fighting with it.

Edit: This may have been the article that sent me in the direction of an asynchronous solution. I believe the problem stated here is one and the same:

XmlHttpRequest double posting issue in Android

Community
  • 1
  • 1
Chuck Spohr
  • 626
  • 4
  • 10
  • Yes, at this time, the 'solution' is to avoid a 30 seconds response time. Either in the method you describe, or an equivalent, or reworking the server side application. – gmh04 Mar 28 '13 at 09:16
3

What about using beforeSend: and complete: AND .ajaxSend() + ajaxSuccess(), also try with 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);
    }
});
Carlos Castillo
  • 907
  • 6
  • 7
  • If the timeout is less that the response time, I get a timeout and a single request. If the timeout is greater that the response time but less than the response time * 2 I get a timeout and two requests. If the timeout is greater that the response time * 2 I get an error and two requests. – gmh04 Mar 22 '13 at 10:29
  • Note: In the third case, the error is exacly 60 seconds after initial request. – gmh04 Mar 22 '13 at 10:37
  • Not very much related, but I'd check that in ANY case the JSON response you get from your /path/to/url script is valid JSON because empty responses doesn't count as valid and it throw an error or could have unpredictable results, at least make sure you send and empty (but valid) JSON, like null or {} (return `json_encode = array();` will suffice on PHP) – Carlos Castillo Mar 22 '13 at 15:50
  • If the response takes less than 30 seconds, everthing works fine. Oh and it works on all other devices I have tested, only Samsung Galaxy S2 does it fail – gmh04 Mar 22 '13 at 16:03
  • please try with the (hopefully) improved answer – Carlos Castillo Mar 22 '13 at 16:09
  • - Valid JSON (check) - beforeSend/complete settings added to control if a second request was triggered (check, it's the SAME request that gives the double GET) Is this jquery mobile ? if so, are you using the last 1.3.0 version ? and again, if so, try downgrading/switching versions (to 1.2.0 for example) to see if something changes. Are you able to do a POST instead of a GET ? not that that will fix things, but I think we might be in the case of a bug here. – Carlos Castillo Mar 22 '13 at 16:47
  • `.ajaxSend()` + `ajaxSuccess()` was added, give that a try ... if that doesn't work I really don't know what else to try man ... – Carlos Castillo Mar 22 '13 at 17:06
2

I've tried this one in my mobile site developing the only problem was in my form and then on my javascript I declared

$("#button_submit").onclick(function(){
   //ajax request here
});

and also dont forget to remove the form attributes like action and method if you're using ajax

I hope it helps you ^_^

Fanckush
  • 143
  • 3
  • 10
Cjames
  • 1,852
  • 1
  • 20
  • 23
2

Click event is being triggered twice. The below code fixes this issue.

$('.selector').unbind('click').bind('click', function () {
 //...
 // Ajax code
 //...
});
Omar
  • 32,302
  • 9
  • 69
  • 112
1
 <a href="javascript:test()">

thats your issue. If you are going to use jquery, use their css selectors!!!!!!!! that href:javascript stuff is buggy across browsers/devices .

Dnaso
  • 1,335
  • 4
  • 22
  • 48
1

Sounds more like a problem with event propagation. I was seeing similar symptoms (albeit on ios) and it came down to the 'touchstart' and 'touchend' events both firing the 'click' event. Have you tried something like this:

$("a").click(function (e) {
    e.preventDefault();
    alert('Clicked');
    test();
});

Hope this helps!
Cheers
JD

0

The issue you are facing is commonly called "bouncing" it's also faced with switches in electronics, when you are pressing and releasing a button the switch is triggered twice, so you need to either set a delay for the function or unbind it once you are done with your click.

You could use Ben Alman's throttle script to debounce your clicks, it's very useful in preventing multiple ajax calls from taking place, combine that with a delay and your issue should be fixed

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
                });
            }

Now call the debounceClick function from the link to fix your issue.

Alternatively you could also use simple plain javascript without the throttle plugin to also achieve your result:

            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);
            }

In this example, bind the click() function to your link.

Pratheek Rebala
  • 375
  • 2
  • 7
0

I faced the same issue, i was binding click event on the submit button and ajax runs twice. Instead of binding an event, i used onClick method on the button like below

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

and it solves my problem.

Exhausted
  • 1,867
  • 2
  • 23
  • 33