Server XHR got received event in JS - javascript

Situation:
Target API is external and may not be changed in any way. I have a JS client that sends some data to the API on client button click. Something like
$.ajax({
type: "POST",
url: "http://api.url/some_resource",
data: {name: 'John', email: 'john#john.com'}
}).done(function(msg) {
if (msg === 'ok') {
alert('Your Callback Request Sent!');
} else {
alert('Error occurred. Please try later.');long
}
});
When I send the request I have to wait to receive the response from the server to see if it was successful and notify the client if it was or was not.
The problem is that I the API is friggin slow and does not reply directly that it received everything and will process the request, but instead is trying to do all the job like sending email and only then replying. Sometimes it takes about 20s for response to be received (the XHR request response).
Is it possible (jQuery or pure JS) to fire something like "request reached server event" so I would be at least sure there were no connection problems?

Is it possible to fire something like "request reached server event"
No - the client does not know of that event. It only knows a) when it has sent the last bit of the request and b) when it has received the first bit of the response. There is nothing in between but waiting.
To the XMLHttpRequest interface there is the following readyState information available:
Val State Description
---------------------------------------------------------------------------------
0 UNSENT open()has not been called yet.
1 OPENED send()has not been called yet.
2 HEADERS_RECEIVED send() has been called, and headers and status are available
3 LOADING Downloading; responseText holds partial data.
4 DONE The operation is complete.
so I would be at least sure there were no connection problems?
Well, if there had been connection problems that are detectable to the client, you would've been notified of them.

Related

How much of `$.post` is blocking?

I have a form collecting some information that I use $.post to handle an ajax request.
$.post(ajaxEndpoint, dataObject)
.done(function (response) {
if (response.status === 'success') {
// Send data to process asynchronously
otherApiCall(response.otherData);
// Redirect to the thank you page
window.location.replace(getThankYouUrl());
}
});
function otherApiCall (data) {
$.post(otherAjaxEndpoint, data);
}
The problem I have, from what I'm guessing, is that it redirects too quickly before the other POST can be made. But I do want it to POST asynchronously then redirect so the user isn't waiting for that second response. I don't care what the result of the second response is. I just want to finish the first response, send a second POST and the redirect immediately to cut down on the user looking at a spinner.
My second $.post seems like it doesn't get sent in time before the redirect happens because I never get the data from it. If I comment out the redirect, I do. I don't want to wait until the second done() but I can't figure how not to. What am I not understanding and/or doing wrong?
Additional Information/Update
I do have control over the server side handling. Is there something on that end that I could do to get a response quickly without waiting for the rest of the processing to finish?
You probably want to let the second post complete and then do the redirect.
A simple fix would be to return the $.post from second method and use done() of the second call to manage the redirect
$.post(ajaxEndpoint, dataObject)
.done(function (response) {
if (response.status === 'success') {
// Send data to process asynchronously
otherApiCall(response.otherData).done(function(){
// second post call now complete
// Redirect to the thank you page
window.location.replace(getThankYouUrl());
}).fail(function(){
// handle failed response
});
}
});
function otherApiCall (data) {
return $.post(otherAjaxEndpoint, data);
}
The best way to send data back to a server without having to wait for it to complete would be to use the navigator.sendBeacon API.
navigator.sendBeacon('/url/to/handler', yourData);
Quote from MDN:
Using the sendBeacon() method, the data will be transmitted asynchronously to the web server when the User Agent has had an opportunity to do so, without delaying the unload or affecting the performance of the next navigation.
Your data will have to be made into a ArrayBufferView, Blob, DOMString, or FormData, and I'm not sure if it is technically a POST request or not, but the request will persist after redirection.
It is currently supported in Firefox 31+, Chrome 39.0+, Opera 26+. For other browsers, you would have to do something else. You can feature-detect like so.
if (navigator.sendBeacon) {
// Use sendBeacon API.
}
else {
// Something else.
}
The redirect is probably cancelling the AJAX request that has been queued, but not yet sent. Try doing the redirect after a timeout, to give the second AJAX call a chance to be sent.
$.post(ajaxEndpoint, dataObject)
.done(function(response) {
if (response.status === 'success') {
// Send data to process asynchronously
otherApiCall(response.otherData);
// Redirect to the thank you page
setTimeout(function() {
window.location.replace(getThankYouUrl());
}, 10);
}
});
I'm not sure how reliable this is, though. Perhaps a better solution would be to perform the redirect when the second AJAX call goes to readystate == 3, which means the server is processing the request. There's no jQuery interface to this, so you'll probably have to do it using the low-level XMLHttpRequest interface.

Strophe Message Sent Acknowledgment Issue

I have implemented OPENFIRE with XMPP + BOSH on my Web based client interface.
When i am sending the message ,i check whether connection is live or not.If it is not live i create new connection and then send.
Sometimes it happens that client send a message and it is not get delivered to server(not opposite client).
So for that i need a strong thing that should inform client that this message didn't reach to server,please send again.
try { // sleep(2000);
Gab.connection.send(message); >
**var request = $msg({
to: jid,
"type": "get",
id: mid
}).c('get', {
'xmlns': Strophe.NS.DISCO_INFO,
'id': mid
});**
console.log(request); >
} catch (err) {
alert("Internet Disconnected ! Click ok to Reconnect SEND");
window.top.location.reload(1);
}
On above code i call message send().After that i call function as mentioned in "XMPP:xep-0184" doc.
but no response i received.
Thank you in advance.
Not sure what a "strong thing" is, but when someone is disconnected in Strophe, you should get errors from the script and it will update the Strophe.Status connection state. Strophe sends a post every 60 secs (unless otherwise specified). In your code it appears you're trying to check support.
You should look for "Strophe.Status.CONNECTED" or "Strophe.Status.ATTACHED" prior to sending if that's your concern. You can also write a handler to manage the errors.
In XEP 0184, you must include:
<request xmlns='urn:xmpp:receipts'/>
So your msg should look like (note, you must include an id per XEP 0184):
$msg({
to: tojid,
from: fromjid,
type: "chat",
id: "sometrackingid"}).c('body').t("bodytxt").up().c("request", {
xmlns: "urn:xmpp:receipts"});
You will then need to modify you message handler or create a separate handler to manage the receipts.

How to handle ajax call when there is no response from the server

I have an ajax call for some data (using jQuery). after the user clicks "submit" (and the ajax call has been sent) I am displaying a "Please wait..." message that disables everything until the request returns (so the user won't double click or click other things and mess things up).
It works great when there is any kind of error - the "Please wait..." disappears and I am displaying the user what went wrong.
But what happens if the server don't return me anything back because of communication error?
The solution I found for that is to set a timeout of 10 seconds for the "Please wait.." message that after that time it disappears and displays and error that "The communication failed". I assume that if the server didn't respond after 10 seconds then it will not respond at all - but that it false assumption.
The problem is - how can I be sure that after 20 seconds the server won't return something back? The scenario that might happen is that the user click submits --> 10 seconds later he get an error message --> 5 seconds later server response and confuses the user
How do I make sure that after I hide the "Please wait.." message nothing will pop up from the server?
when you send a request to a server. a connection is opened and its kept open unless the server responds.
1.if due to some error on the server side it cannot respond then a response code of 5xx is sent back generally (503)
2.if due to some connection issues the connection is terminated prematurely then also jquery would take that as an error.
1.so if you wanna wait for the server to send a request or connection termination (which ever occurs earlier) then u can use the completed option in the jquery ajax.
2.and if you are in a condition in which server isnt responding even after 20 secs and you think that it should have responded by now use timeout.
3.finally if your problem is that you are using some kind of customized(hand made http server) which doesn't end a request even if it encounters some error then atleast customize it enough so that it sends back some response code(because this is HTTP model of request and response)
You can handle something like this
if ( request.readyState == 4 ){ // 4 is "complete"
if ( request.status == 200 ){
// HTTP OK, carry out your normal Ajax processing
// ...
}else{
// something went wrong, report the error
error( "HTTP "+request.status+". An error was ยป
encountered: "+ request.statusText );
}
}
(or)
$.ajax({
type: "post",
url: "somepage.html",
success: function (data, text) {
//...
},
error: function (request, status, error) {
alert(request.responseText);
}
});
Generate a unique token when you fire a request,
keep a list of valid tokens,
remove tokens when the request times out/fails,
check if token is still valid before executing success/error callbacks.
The same pattern can be adapted for a situation when you need to send frequent repeating requests (e.g. autocompletion/result filtering) and only the latest one's handler should fire.

How do I trigger the "error" callback in backbone.js collection.create?

collection.create(data, {
success:function(){ ... },
error: function(){ ... },
});
If I save it, and it hits the server, but the server validates an error, how do I let the client know? It seems that no matter what, "success" is called.
The error callback is triggered on a 4xx or 5xx HTTP response.
What are the HTTP response codes of your server errors?
The latest Backbone docs have a small blurb about this:
If a server-side validation fails, return a non-200 HTTP response code, along with an error response in text or JSON.
I think you need to make the server send a response code of not 200 ok.. like 500.
http://documentcloud.github.com/backbone/#Model-save

Ajax - I need to check whether a valid session exists before every AJAX requests

I'm working on a project which uses user authentication. I'm facing a issue with my AJAX requests if there is no authenticated session present when the request is made.
I've a session timeout of 3min, so if the user keeps idle for 3 min then do some action which causes a AJAX request then the request will fail and return a 403 error. Here What I'm planning to do is intercept all the AJAX request from the page and sent a ping to the server which will return a JSON object saying whether there is a valid session. If there is one then the client will continue with the current request else it will reload the current page which will take the user to the login page and the user has to provide the credentials again.
Here is my implementation.
$("#param-ajax").ajaxSend(function(evt, request, settings) {
var pingurl = GtsJQuery.getContextPath() + '/ping.json';
var escapedurl = pingurl.replace(/\//g, "\\/");
var regexpr1 = eval('/^' + escapedurl + '\\?.*$/');
var regexpr2 = eval('/^' + escapedurl + '$/');
// Proceed with the ping only if the url is not the ping url else it will
// cause recursive calls which will never end.
if (!regexpr1.test(settings.url) && !regexpr2.test(settings.url)) {
var timeout = false;
$.ajax({
url : pingurl,
cache : false,
data : {
url : settings.url
},
async : false,
complete : function(request, status) {
if (status == "error") {
try {
// GtsJQuery.getJsonObject() converts the string
// response to a JSON object
var result = GtsJQuery
.getJsonObject(request.responseText)
if (result.timeout) {
timeout = true;
return;
}
} catch (e) {
// ignore the error. This should never occure.
}
}
}
});
// Reload the window if there is a timeout -- means there is no valid
// sesstion
if (timeout) {
window.location.reload();
}
}
});
Here everything work fine included the window.location.reload(), but the original ajax request is not aborted. Since the original AJAX request is not aborted after the page reload is triggered, the AJAX request also is sent to the server. I want some mechanism which will allow me to abort the original request if the timeout turns out to be true.
This post offers some answer, but the issue remains with the third party plugins like datatables which uses AJAX. We cannot write a error handler for those AJAX requests.
Thank you.
If I am understanding the situation, you do not need any of that. In your original ajax request, simply add an error function that will redirect the user.
errHandler = function(XMLHttpRequest, textStatus, errorThrown) {
if( textStatus.match(/forbidden/i) ) {
redirectUserToLoginHere();
}
}
$.ajax({
success: yourFunctionHere,
error: errHandler
})
Then you might be able to make some ajax wrapper which always has that errHandler so you don't have to place it in every single ajax call.
EDIT:
after some experimentation, if an 'ajaxSend' handler throws an Error, then the original request will never be sent.
Also, if the handler does
document.location = '/login';
then the original request is never sent.
Hopefully that helps :)
I changed my concept now, I'm checking for the xmlHTTPRequest in the server side using the request header 'x-requested-with'.
If it is a xmlHTTPRequest then 'x-requested-with' will have the value 'XMLHttpRequest'. Both the javascript libraries(EXTjs and jQuery) I'm using sets this header correctly.
Here is my server side code
boolean isAjaxRequest = StringUtils.endsWithIgnoreCase(request.getHeader("x-requested-with"), "XMLHttpRequest")
EDIT
If the given request is a ajax request the response will be json data which will have status 403 and it will contain a key called timeout with value true
ex: {timeout: true, ....}
Then we will handle this in the $.ajaxError() event handler will handle the error. If the error status is 403 and the timeout value is true then I'll reload the page.

Categories