user1768233 user1768233 - 1 month ago 5
Ajax Question

What happens when no response is received for a request? I'm seeing retries

The question I have is probably more of a browser related question I think, but its a pretty fundamental one I'd like to find the answer too as I venture into building a web application.

In my client side code I am doing an

$.ajax
call. This Post can take a while to respond. What I'm seeing is after a certain amount of time the request is being send again.

I thought it was my
$.ajax
call sending it again, but no matter how many times I see the POST request on the server, I only see the
beforeSend
callback called once. I am fairly sure my code isn't sending it more than once, so I think its the browser retrying?

I know my server is getting the request more then once as I ran up Wireshark and can see the post request multiple times. So my assumption is this is something to do with HTTP? I.e., if a response isn't received within a certain amount of time then the request is resent?

Here is a sample of my call below.

$.ajax({
async: false,
type: 'POST',
url: '<%= url_for('importDevice') %>',
data: { device: val },
retryLimit: 0,
//callback
success: function(data) {
alert('calling import');
if ( data == 'nomaster')
{
// Display a warning toast, with a title
toastr.warning('You must set the Master Key first!', 'Warning');
$.ismasterset = false;
//reset the form contents after added
} else
{
$("div#content").html(data);
}
},
beforeSend: function(){
alert('in before send');
}
});


This is all of the relevent code, 'retryLimit' isn't being used, I just haven't removed it from my code and yes the problem was there before I put it in.

EDITED with output from client and server.

ok I installed 'Live Http headers for Firefox'.

In the 'Generator' tab I see the one single call

'#request# POST http://testhost/importdevice'


I don't see the POST in the 'headers' section though, maybe thats because there's no response?

In my webserver though I see 2 calls about 22 seconds apart.

[Sun Jan 13 03:08:45 2013] [debug] POST /importdevice (Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20100101 Firefox/17.0).

[Sun Jan 13 03:09:07 2013] [debug] POST /importdevice (Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20100101 Firefox/17.0).

I can also see these same calls in wireshark...

This is why I was asking if this is normal behaviour to try to resend the request if a response doesn't come back, in a similar fashion to a TCP handshake and the SYN retransmission.

NEW UPDATE

It doesn't seem to have anything to do with my Ajax call. If I create a button with a simple HREF.

i.e
"a href="/importdevice?device=serverA" class="btn btn-success">TestDirect

Then in my 'Live HTTP headers output I get... just one instance.

#request# GET http://172.16.118.15/importdevice?device=serverA


But once again in my server logs I get.

[Sun Jan 13 03:20:25 2013] [debug] GET /importdevice (Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20100101 Firefox/17.0).
[Sun Jan 13 03:20:48 2013] [debug] GET /importdevice (Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20100101 Firefox/17.0).


And in wireshark on the server

I'm seeing it twice as well... and as expected my server code is called twice too... This is REALLY confusing to me.

Answer

Checkout this blog post that explains what is happening: http://geek.starbean.net/?p=393

According to HTTP/1.1 RFC 8.2.4:

If an HTTP/1.1 client sends a request which includes a request body, but which does not include an Expect request-header field with the “100-continue” expectation, and if the client is not directly connected to an HTTP/1.1 origin server, and if the client sees the connection close before receiving any status from the server, the client SHOULD retry the request.

Make sure you design your web app to tolerate these extra requests. And if you want the ajax request to do something only once, such as writing something to a database, then you need to design the request as idempotent. See: What is an idempotent operation?

Also, this highlights the differences between GET and POST operations: http://www.cs.tut.fi/~jkorpela/forms/methods.html

As a general design practice:
-GET operations should be designed as idempotent
-POST operations should be used for writing to databases, etc.