Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safari double-submitting ajax calls

I have noticed that Safari 5.0.5 (6533.21.1) seems to be submitting duplicate ajax calls. When I run the following reduced test case:

// jquery 1.6 include
$(document).ready(function() {
    setTimeout(function(e) {
        var req1 = $.getJSON('/api/private/customers.json');
        console.log('req1 sent');
    }, 2000);
    setTimeout(function(e) {
        var req2 = $.getJSON('/api/private/customers.json');
        console.log('req1 sent');
    }, 4000);
});

the Safari Resources panel and the console show two xhr requests going out, but my server log shows three xhr requests coming in:

XX.XX.XX.XXX - - [10/May/2011:16:50:40 -0400] "GET /api/private/customers.json HTTP/1.1" 200 183 "https://sub.mydomain.com/customers" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
XX.XX.XX.XXX - - [10/May/2011:16:50:42 -0400] "GET /api/private/customers.json HTTP/1.1" 200 183 "https://sub.mydomain.com/customers" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
XX.XX.XX.XXX - - [10/May/2011:16:50:42 -0400] "GET /api/private/customers.json HTTP/1.1" 200 183 "https://sub.mycomain.com/customers" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"

When I make the same request with the latest version of Firefox, I correctly get two requests:

XX.XX.XX.XXX - - [10/May/2011:16:52:00 -0400] "GET /api/private/customers.json HTTP/1.1" 200 183 "https://sub.mycomain.com/customers" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
XX.XX.XX.XXX - - [10/May/2011:16:52:02 -0400] "GET /api/private/customers.json HTTP/1.1" 200 183 "https://sub.mycomain.com/customers" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"

This behavior does not seem to happen on the first request, but all subsequent requests are sent in duplicate. Does anyone have any idea what is going on? Efforts to detect the extra requests in the js were futile.

like image 378
user747594 Avatar asked May 10 '11 21:05

user747594


3 Answers

I guess we won't know if it's a bug or a feature... Anyway Safari (as it is in 10.0.2 version) still do perform conditionnal request as explained by Dan Manastireanu. The way I found to have a request not duplicated is to set a 'If-Unmodified-Since' header with the current request time. (Alternatively you can also add a timestamp parameter in url, as mentionned again by Dan Manastireanu)

I downvoted the setRequestHeader('Connection', "close") because it is a forbidden header name and throw a Refused to set unsafe header "Connection" error.

So a basic request looks like this:

var get = function(url, callbackSucess, callbackError) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.timeout = 10000;

    var now = new Date().getTime();
    request.setRequestHeader('If-Unmodified-Since', now);

    request.onreadystatechange = function() {
        if (request.readyState !== 4) {
            return;
        }
        if (request.status === 200) {
            callbackSucess(request.status);
        } else {
            callbackError(request.status);
        }
    };
    request.onerror = function (error) {
        callbackError(error);
    };
    request.ontimeout = function () {
        request.abort();
    };
    request.send(null);
}
like image 170
maiwenn Avatar answered Nov 03 '22 14:11

maiwenn


I believe the browser is making a conditional GET request for the second call (also see the 304 response status).

On the first call there is no cached response in the browser, so it does a normal request.
On the second request the browser does first a conditional GET request, and upon seeing that its cached response is out of date it has to repeat the GET request.

As far as I know jQuery has a builtin fix for this (it automatically appends a parameter to the request url, something like _=123456789). I don't know why this is not working here.

You could try to append a request param by hand like this: '/api/private/customers.json?v='+(new Date().getTime())
Or you could try and use jQuery.ajax with cache:false, and dataType:'jsonp'

You can open Safari's Developer Tools (Web Inspector), and check the Network tab. It will tell you more about the request and response.

like image 3
Dan Manastireanu Avatar answered Nov 03 '22 15:11

Dan Manastireanu


Adding a Connection: Close header to the API response fixes the problem.

like image 2
user747594 Avatar answered Nov 03 '22 14:11

user747594