XHR throws timeout error and does not execute onTimeout event - javascript

I am coding a native JavaScript application in which I make simultaneous AJAX requests to multiple unique servers every minute. When a server is offline, I intended my program to handle this through the function registered to the XHR.ontimeout event.
Below is a quick JS sample I wrote to demonstrate my problem. Monitor the console and you will see only sometimes requests to an offline address trigger the ontimeout event. Other times ERR_CONNECTION_TIMED_OUT occurs. I would like to have a timeout handler that executes every time I call my function and the server is offline.
<!DOCTYPE html>
<html>
<TITLE>Timeout Error Demo</TITLE>
<body>
<script>
var i=0;
var xhr;
function main(){
console.log('Main run #'+i);
i++;
xhr=new XMLHttpRequest();
xhr.open("GET", "http://1.1.1.1", true); //this address is always offline
xhr.timeout=2000;
xhr.ontimeout=function(){
console.log("timed out");
}
xhr.onreadystatechange=function(){
if (xhr.readyState==4 && xhr.status==200){
console.log("done");
}
}
xhr.send(null);
setTimeout(main,5000);
}
main();
</script>
</body>
</html>

As i see it the core of the problem here is that you misunderstand how the ontimeout event works. So i will try to explain how the browser works with ontimeout and what the difference is with onerror.
ontimeout
The ontimeout event will to thrown when a request is made to the server and that request get succesfully through to the server. Then if the server takes a long time to response the timeout event will get thrown by the HTTPRequest.
Ex:
Client side
xhr.timeout = 2000;
xhr.send();
xhr.open("GET", /somecontroller/IAmAReallySlowEndpoint, true);
xhr.ontimeout = function() {
console.log("I get called because the server was to slow to response on a succesfull request");
}
Server side endpoint (C#)
public bool IAmAReallySlowEndpoint()
{
Thread.Sleep(4000);
return true;
}
you call a server side endpoint which does not answer within 2 seconds then the ontimeout event will get thrown.
onerror
The onerror event will throw if an error in the http request happens which is the case in your example. You want to call an url that is down. Calling an url that is down will throw an error and thereby the onerror event is called.
So when you write that it works when do you:
xhr.ontimeout = xhr.onerror
You are just passing the onerror event to the ontimeout.
So to solve your problem with doing stuff if one of the endpoints you are requesting is down you should implement some retry logic kinda like you already have with a setTimeout() but deciding if the server is down or not should be based on numbers of failed request to the server instead of the ontimeout.

It's .ontimeout, not .onTimeout. Or .addEventListener("timeout", …).

Related

xmlHttpRequest.onerror handler use case

What sort of situations could cause this handler to be called? I'm not finding any instance where this method throws an error.
I tried with the device offline, I get xmlHttpRequest.status = 0 but no error.
Question is what sort of situations can I create in order to test functionality of this handler.
var xmlhttp = new XMLHttpRequest(),
method = 'GET',
url = 'https://developer.mozilla.org/';
xmlhttp.open(method, url, true);
xmlhttp.onerror = function () {
console.log("** An error occurred during the transaction");
};
xmlhttp.send();
From: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/onerror
Your question is the perfect example. Just try your code from your web developer console while on this very page.
Here, try it yourself:
var xmlhttp = new XMLHttpRequest(),
method = 'GET',
url = 'https://developer.mozilla.org/';
xmlhttp.open(method, url, true);
xmlhttp.onerror = function () {
console.log("** An error occurred during the transaction");
};
xmlhttp.send();
When dealing with any network based IO all kinds of things could happen. Cross-Origin requests are only one. What if the server is offline, DNS lookup fails, a router between you and the server that is critical point of failure goes down?
Since an XHR call is for a server response, onerror would come into play when there is an error at the server. Changing your client to be offline doesn't simulate a server error.
Suppose the server resource gets moved and the server responds with a 404 error? What if the server times out? What if the request itself is malformed and causes the server to throw an error?

Getting Access Denied Error

Getting Access Denied Error on https in IE. while executing ajax call (to my server1) response which has another ajax call While my Ajax call url is on http .By implementing cors I able to execute on http.Tried JSONP also but then it execute my response till it find another ajax call .How to solve ?
below is on myserver1
alert('aaa');
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', 'http://myserver2.com', true);
xhr2.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr2.send();
xhr2.onload = function () {
alert('fff');
var appCreds = xhr2.responseText;
alert(appCreds);
};
alert('xxx');
In addition to the trusted site requirement I found that the problem was not fixed until I used the same protocol for the request as my origin, e.g. my test site was hosted on a https but failed with any destination using http (without the s).
This only applies to IE, Chrome just politely logs a warning in the debug console and doesn't fail.

Load error is not captured by try catch block

I have a code like:
try{
...
} catch(error){
...
};
In try block, there is a function call that makes a request to a server. When there is no resource on the server, an error is raised (as I can see in Google Chrome's developers tool):
Failed to load resource: the server responded with a status of 404 (Not Found)
and I am trying to catch it in the catch block, but the error is not captured.
Is it a feature of JavaScript that load error is not captured by try catch block?
Typically, when requesting information from a server (for instance, via ajax, by setting the src of an img element, etc.), you don't get an exception, but you do get an error event or callback, not least because the code doing the request finishes before the request does, so it's impossible to throw an exception at that point. Since you haven't shown how you're requesting the information, it's impossible to be more specific, but this is why you're not getting an exception.
For instance, with an ajax request, if there's an error you see the ajax request complete but with the statusCode of the XMLHttpRequest object being an error status code, rather than 200. E.g.:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// The request is complete; did it work?
if (xhr.statusCode >= 200 && xhr.statusCode < 300) {
// Yes
}
else {
// No, got a code outside the 2xx range
}
}
};
xhr.open("GET", "/your/url/here", true);
xhr.send();

Polling from a JavaScript worker using XMLHTTPRequest

I’m trying to create a worker that does the following simultaneously:
Sends an XMLHTTPRequest to a server to perform a task (which may
take a long time)
Sends an XML HTTP Request Message every X seconds to get an update on the process until the process (1) is complete.
What i have so far is below. But it doesnt poll. The first part is successfully executed. The second bit runs just once. Does anyone know what i'm doing wrong?
onmessage = function (e) {
e.data.params.task = "runTask"; // The server understands this. This performs(1)
// Sends an asynchronous request to perform (1)
var xhr = new XMLHttpRequest();
xhr.open('POST', e.data.url, false);
xhr.setRequestHeader("Content-type", "application/json");
xhr.send(JSON.stringify(e.data.params));
// initialise polling
var interval = 500;
// Poll until (1) is complete
(function poll(){
if (xhr.readyState != 4){ // while (1) is yet to be completed..
e.data.params.task = "getProgress";
// Send another request to the server to get an update on the first process
var pollxhr = new XMLHttpRequest();
pollxhr.open('POST', e.data.url, true);
pollxhr.setRequestHeader("Content-type", "application/json");
pollxhr.timeout = interval;
pollxhr.ontimeout = poll; // This should cause the process to poll
pollxhr.onreadystatechange = function(){
e.data.progress = pollxhr.responseText;
postMessage(e.data);
};
pollxhr.send(JSON.stringify(e.data.params));
}else{
e.data = xhr.responseText;
postMessage(e.data);
}
})();
};
The problem is with the first call
xhr.open('POST', e.data.url, false);
^^^^^
Looking at the method you can see the third parameter is async
open(DOMString method, DOMString url, optional boolean async, optional DOMString? user, optional DOMString? password);
By setting it to false, you are telling it to run synchronously, which means nothing else will happen until it the call is returned. That results in your polling code running after the first call is returned. Set it to run asynchronously and use the onreadystatechange to get when it is completed!

Problem: XMLHttpRequest - handle server connection lost

How do I handle the scenario where I making a synchronous request to the server using XMLHttpRequest and the server is not available?
xmlhttp.open("POST","Page.aspx",false);
xmlhttp.send(null);
Right now this scenario results into a JavaScript error:
"The system cannot locate the resource specified"
Ok I resolved it by using try...catch around xmlhttprequest.send
:
xmlhttp.open("POST","Page.aspx",false);
try
{
xmlhttp.send(null);
}
catch(e)
{
alert('there was a problem communicating with the server');
}
Try the timeout property.
xmlHTTP.TimeOut= 2000
You don't check for properly returned status. By the code you gave you are doing a GET request.
To properly check the status of your request, you must create an event handler for the onreadystatechange event and then inside it check if the readyState property is equal 4 and then inside the method if the status is 200.
You can find a detailed explanation here :Ajax Tutorial by Mozilla
xmlhttp.onreadystatechange=function()
xmlhttp.open("GET","Page.aspx",false);
{
if (xmlhttp.readyState==4)
{
if (xmlhttp.status==200)
{
//Ajax handling logic
}
}
}
xmlhttp.send(null);

Categories

Resources