21

I've got a jQuery client making an Ajax post request to a Spring Controller. On the server side, no error has been logged. On the client side, the request is stuck on pending a very long time, minutes, then might fail either with ERR_SPDY_PROTOCOL_ERROR or ERR_CONNECTION_CLOSED.

This problem is reproducible on Chrome, but not on Firefox. Verified affected version is 70.0.3538.77, there may be others too. Also, the problem occurs on a specific deployment of the application and not elsewhere, development or production.

The client sends HTTPS 2 requests on that environment. On the development environment it is HTTP 1.1. On the server, all requests are recorded as 1.1.

For no apparent reason, the requests started going through, but this is a recurring problem and would like to solve it. Since the problem started happening, I can't reproduce it and check if the problem is too many connections to the server (more than 6). I use three DNS servers, the last one of which is Google's 8.8.8.8.

I am looking for a code fix or a hint whether this could be related to server setup. I am almost certain that it is a combination of client code and networking.

What the problem is not:

What I've tried unsuccessfully:

What doesn't answer the question:

On the client side, I've tried clearing browser data, flushing sockets and private browsing / incognito.

The only thing that sometimes, rarely, bypasses the error is going on incognito and flushing sockets and emptying cache from chrome://net-internals/#events

var formData = new FormData();

formData.append( /* ... */ );

//...

$.ajax({
    type: "POST",
    url: "/somepath/update",
    cache: false,
    data: formData,
    contentType: false,
    processData: false,
    success: function(result) {
        //...
    },
    fail: function(result) {
        //....
    },
    error: function( jqXHR, textStatus, errorThrown ){
        alert(textStatus + ":" + errorThrown);
    }
});

A separate request using $.post was going through:

$.post("someotherpath/update", $("#someForm").serialize())
    .done(function (data) {
        //...
     })
     .fail(function (data) {
         //...
     })
     .always(function () {
         //...
     });

Server side:

@RequestMapping(value="/somepath/update", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public @ResponseBody String update(ModelClass model) {
    JSONObject result = new JSONObject();
    //...
    return result.toString();
}

If it's relevant, there are the following filters. I'm afraid I can't post more of them at the moment:

@Configurable
public class Filter1 extends OpenEntityManagerInViewFilter implements Filter{

    public void doFilterInternal(HttpServletRequest httpReq, HttpServletResponse httpResp, FilterChain chain)
        throws ServletException, IOException {
        //...
    }
}


@Configurable
public class Filter2 extends OncePerRequestFilter implements Filter{

    public void doFilterInternal(HttpServletRequest httpReq, HttpServletResponse httpResp, FilterChain chain)
        throws ServletException, IOException {
        //...
    }
}

@Order(/* very small integer */)
public class Filter3 extends OncePerRequestFilter {

}

Expected result is that the code should go through the success callback. Instead the request is stuck on pending for minutes, then enters the error callback.

N Sarj
  • 374
  • 3
  • 11
  • 2
    And your jquery version is...? :D And have you tried using postman or curl to send a basic request to confirm the server is responding OK to the same type of request? – Cody G Jan 07 '19 at 14:25
  • Thanks for your comment @CodyG. Version is 1.7.2. I haven't tried postman, but I would guess that trying with Firefox is enough. – N Sarj Jan 08 '19 at 15:42
  • Have you tried an updated version of jquery or setting a timeout on the ajax request? The point of trying it with another application is to separate the issue with the library or your server. ... or with the client. – Cody G Jan 08 '19 at 15:43
  • I will see if I can upgrade jQuery. I understand why it is important to try with another application/client. – N Sarj Jan 08 '19 at 16:36
  • Could this be improved with an asynchronous request and the use of a Promise? – Yvonne Aburrow Jan 09 '19 at 21:49
  • 1
    Something to consider: I've had various problems because I turned on a flag in chrome://flags/. The flag `experimental web platform features` turns on some new headers some web servers can't deal with. Try to reset those flags when testing as well. – Sandro Jan 13 '19 at 10:00
  • 2
    Could you please have a look at chrome developer tools (press F12 on Win) then **Network** tab, and try to run your code. It should display the data you're sending and any errors that would come up, and let us know what's the result. Also try to compare the output on Chrome/Firefox/Chrome incognito – Ivan Satsiuk Jan 15 '19 at 07:44
  • @Sandro, thanks. It's off though. – N Sarj Jan 15 '19 at 08:07
  • @IvanSatsiuk, I've done that already. – N Sarj Jan 15 '19 at 08:08
  • 1
    Check the protocol. if the page url is "https" then the backend code which you are trying to access also should be secured. i have faced similar issue. – Jackson Jan 16 '19 at 22:04
  • @Jackson, thank you very much! I was mistaken though. The requests are plain HTTP. I'll update my question. – N Sarj Jan 17 '19 at 08:41
  • @Jackson, it turns out that on the problematic environment, the requests are HTTPS/2.0. I'll keep you posted. If this leads somewhere, I'll tell you to post an answer for me to accept. Thanks again. – N Sarj Jan 17 '19 at 09:22
  • Did you noticed that in your second ajax call (post) you use promises, and on the first you use the deprecated methods? – Merak Marey Jan 31 '19 at 09:18
  • @MerakMarey, thanks. I had noticed the differences, I did not realize I was using deprecated APIs. However, I don't think that's the cause, because the server is not doing what it's supposed to do. It's not just an issue of not getting a response. I've read that ajax and post are equivalent. The substantial difference is using FormData in one case and form.serialize() on the other. I don't think I can eliminate the FormData though. – N Sarj Feb 01 '19 at 12:26
  • @NSarj Not refering to the ajax and post ...refering to `sucess:` and `.done` ..first one is the old methods for handling responses..second is the recommended one, based on promises... – Merak Marey Feb 04 '19 at 17:48
  • Try adding this option: `async: false` – mliakos Mar 19 '19 at 16:34
  • @alittlebyte, thanks for your suggestion. – N Sarj Mar 20 '19 at 08:36
  • Did that solve the problem? – mliakos Mar 24 '19 at 21:41
  • @alittlebyte, I haven't been able to reproduce the problem lately. I haven't tried your suggestion after you posted it, but I think I had tried it when the problem first occurred. It had not worked. Thanks. – N Sarj Mar 26 '19 at 15:04

1 Answers1

2

$.post is calling $.ajax under the covers just defaulting several of the options.

$.post defaults contentType to "application/x-www-form-urlencoded; charset=UTF-8" which would be consistent with your serialized form data payload.

Your call to $.ajax sets contentType to false -- which may cause the browser to send a pre-flight OPTIONS request to the server, which may be causing the difference in behavior you're experiencing.

I would suggest reading the details on jQuery.ajax() and the various behaviors based on options passed here

Michael Angstadt
  • 880
  • 10
  • 18
  • Thanks for your answer. I need to set the contenttype to false because I'm sending some files. But you're right. And it might have been a cross domain request (due to a DNS redirect). Unfortunately I have no way of knowing now. I will up-vote your answer since it's helpful, but I can't accept it. – N Sarj Jun 04 '19 at 09:27
  • If you're uploading files it'd be best practice to handle that outside the form data postback. – Michael Angstadt Jun 04 '19 at 18:15