26

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</a>

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.

Tim Abell
  • 11,186
  • 8
  • 79
  • 110
user1768233
  • 1,409
  • 3
  • 20
  • 28

2 Answers2

28

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.

Community
  • 1
  • 1
BigMacAttack
  • 4,479
  • 3
  • 30
  • 39
  • thank you! that was exactly what I was looking for..plus more! – user1768233 Jan 16 '13 at 22:30
  • So as per HTTP specifications, even non idempotent requests i.e. POST can be retried by the client – Yadu Sep 20 '13 at 16:48
  • @Yadu Yes, even POST requests can be retried by the client (as experienced by the question asker). But it's not accurate to call *all* POST requests non-idempotent. There are occasions where one might want to design a POST request as idempotent. Be sure to read the very last section at the bottom of [this page](http://www.cs.tut.fi/~jkorpela/forms/methods.html); the section entitled *"Possible reasons to use "POST" for idempotent queries"*. – BigMacAttack Sep 20 '13 at 17:59
  • 8
    So, this is marked as answered, which I guess it is, but no one actually says if I can do anything about it other than do a lot of work on my server side to handle duplicate requests. Is there no way to tell browsers NOT to resend POST requests or disable their timeouts--preferably from javascript/ajax? – BoB3K May 04 '16 at 18:41
  • I have the similar problem now. Say the 1st request comes to server, the server need 3 minutes to process. After 2 minutes, the 2nd request comes in. My server will return 400 immediately. After another 1 minute, the server will return 200 (the 1st request finished). Is that correct? For now the problem is the client shows error when getting the 400 response. it will not wait for the 200 response. – Kaman Wu May 17 '17 at 15:53
0

Why are you setting a callback if your request is not async?

If you want a sync process put beforeSend code before the call and the success callback simply after the call.

If you want an async approach then set async: true

Also this line of code is wrong:

url: '<%= url_for('importDevice') %>',

Look at the quotes: should be

url: '<%= url_for("importDevice") %>',

Maybe those suggestions won't solve the problem but will point you in the right direction. The problem may be somewhere else than in the code posted...

Going back to your question: Could it be the browser? I don't think but who knows what's out there!!... what's the browser? Have you tried with another one?

I'd suggest trying with Firefox and using the Live httpHeaders plugin (very easy to setup and use). You'll see what's going out from the client side, intead of see what's coming in from the server side.

Paolo
  • 15,233
  • 27
  • 70
  • 91
  • Thanks Paolo, Yeah I want async off. My browser is chrome, I've also tried safari and see the same behaviour. In chrome under development tools I see the one POST with the status 'PENDING'. However in my server logs and in wireshark I see the POST request come through twice. Thanks I'll install the Live httpHeaders plugin and see if that helps – user1768233 Jan 13 '13 at 10:51
  • Update above. It seems its nothing to do with Ajax...now I'm really lost. – user1768233 Jan 13 '13 at 11:29