Right now, I have
request.onreadystatechange = function () {
if(request.readyState != 4) return
if(request.status == 200) {
// present request.responseText
} // else present error
}
However, there is a possibility that, for large response bodies, there will be a partial success.
There are two situations I see where this could happen:
The TCP socket is terminated, perhaps due to unstable network conditions.
I call request.abort() when a timeout period has expired.
In either situation, it is possible to have already received a partial response, in which case I think that request.status would be set, and request.responseText would provide truncated content.
How can my onreadystatechange function distinguish between a successful (complete) response, or a response that was interrupted?
(With JSON this is easy to detect, because JSON.parse would throw an error if the response was truncated, but for HTML or plain text, I'm looking for a more official indicator.)
Related
I'm trying to submit a form and get the results inpage using AJAX. I call a JS function onsubmit which makes the AJAX call, and includes this code:
request=new XMLHttpRequest();
/* set up request here */
request.onreadystatechange=function() {
if (request.readyState == 4 && request.status == 200) {
/* do what I need */
alert('Success');
} else {
/* do what I need */
alert('Failed');
}
}
However, the Failed alert shows up multiple times (3 at least) before the Success one, so I guess I'm getting many different statuses before the successful one? How can I check which ones I get, and what to expect when the submission is failed? Thanks.
The request goes through four phases. The readyStates. Every time the readystate updates it fires the event. 0 indicates a failure and 4 indicates that the request has finished. the status returns the http code. 200 indicates success. There was an answer and it returned a request body. All other codes indicate there was something wrong on the server side. Eg. 404, 403, or 500. You can safely ignore the other readystates. But catch any status other than 200 as failure.
You only ever get one status, but you get multiple states.
Check to see if the readyState is 4 or 0 (since either of those states indicate that there is no more of the response to wait for).
Then throw an error if it is 0 or test the status if it is 4.
If the readyState is any other value, then ignore it (unless you want to do stuff in other states).
So I'm creating a mobile application using Intel XDK, I am sending a JavaScript POST request of a username and password. I also did some research on the HTTP status codes and found this:
200 OK - Standard response for successful HTTP requests. The actual response will depend on the request method used. In a GET request, the response will contain an entity corresponding to the requested resource. In a POST request the response will contain an entity describing or containing the result of the action.
201 Created - The request has been fulfilled and resulted in a new resource being created.
202 Accepted - The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place.
So I would assume that when a new user is inserted through a POST request the status would be 201. However when I had this code:
XMLHTTP.onreadystatechange = function () {
if (XMLHTTP.status == 201) {
alert("User created.");
} else {
alert("Error!");
}
}
It would show the "Error!" and not "User created." But when I added this on to the code:
XMLHTTP.onreadystatechange = function () {
if (XMLHTTP.status == 201 || XMLHTTP.status == 200) {
alert("User created.");
} else {
alert("Error!");
}
}
It showed "User created." So I was wondering how come the status is 200 even though I'm sending a POST request to insert in to a database.
Secondly, it alerts the "User created." 4 times? Is that because it is in the function onreadystatechange so it changes each time and is alerted? If so I can I make it so that it only alerts one? Should I have an if statement wrapped in a setinterval as shown below:
setInterval(function () {
if (XMLHTTP.status == StatusNumberHere) {
alert("Blah");
}
}, 10);
Very few websites use those headers, your back-end probably just sends a 200 even though the request was successful in inserting data.
About your second question, the reason your alert is triggered four times is because onreadystatechanged is called four times, each with a different readyState:
Server connection established
request received
processing request
request finished and response is ready
So you probably want to add XMLHTTP.readyState === 4 to your if statement so it in the end becomes:
XMLHTTP.onreadystatechange = function () {
if (XMLHTTP.status === 200 && XMLHTTP.readyState === 4) {
alert("User created.");
} else {
alert("Error!");
}
}
The status returned is based on how the server decides to handle it, in most cased you will simply get a success (200), so there is no issue or abnormality with what you have done.
setInterval = hack, avoid at all costs unless implementing some actual interval function.
You can check the the readystate of the XMLHTTP request with
XMLHTTP.readyState == 4
to filter out only the completed event.
Here is a list of the ready state events:
http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp
From the reference I read in MDN, it says
If TRUE (the default), the execution of the JavaScript function will continue while the response of the server has not yet arrived.
This is the A in AJAX.
I have been using AJAX but then I was a little confused when I read that. I think the problem may be that I am not understanding AJAX concept clearly. I know of course AJAX does not refresh the page which means the connection to the server and the response are completely done in the background.
But what I can imagine happening according to that reference is that if I have a code like this in my JavaScript:
//true, therefore process the function while server retrieves url
var xmlResponse;
var url = "http://example.com/file.xml";
xml_req.open("GET", url, true);
xml_req.onreadystatechange = function() {
if(xml_req.readyState == 4 && xml_req.status == 200) {
if(xml_req.responseText != null)
xmlResponse = xml_req.responseXML; //server response may not yet arrive
else {
alert("failed");
return false;
}
};
xml_req.send(null);
Doesn't that mean xmlResponse could be undefined in the sense that the server is still retrieving the data? Could somebody explain what really is the flow of the execution in AJAX technology? Thanks in advance.
I wrote a more detailed article here, but this is the basic idea.
Setting it to true means you are making an asynchronous request. That means the code does not pause until the http request is complete. A synchronous call locks up the browser so nothing else runs. That can cause problems, so people prefer asynchronous.
The XHR object updates us on what it is doing. It gives us the updates with the onreadystatechange event. We register a function with it so we can keep track of its status. The onreadystatechange gets called 4 times. Each with a different state
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete
The data is available to us when the readystate is 4.
Now in the code you posted, it is checking for the complete state and it makes sure that the status is 200 [ok]
if(xml_req.readyState == 4 && xml_req.status == 200){
The value for xmlResponse will be undefined if you try to use it somewhere else in the code before it is returned. An example
ml_req.send(null);
alert(xmlResponse );
One of the very first articles on the XMLHttpRequest article might be a good read for you. Apple Article on xmlhttpreq
The important thing to understand is that your onreadystatechange handler is not executed immediately. And it is executed more than once. It may be easier to conceptualize, if you break the pieces out into individual functions:
function makeRequest(url)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = receiveResponse;
xhr.send();
}
function receiveResponse(e)
{
if (this.readyState == 4)
{
// xhr.readyState == 4, so we've received the complete server response
if (this.status == 200)
{
// xhr.status == 200, so the response is good
var response = this.responseXML;
...
}
}
}
First, makeRequest is called and then exits. Then, as soon as we hear anything back from the server, receiveResponse is called. Each time, we check to see if the response is fully received, and only then do we continue to process that response.
I'm completely new to the javascript and ajax world but trying to learn.
Right now I'm testing the XMLHttpRequest and I can't make work even the simplest example. This is the code I'm trying to run
<script type="text/javascript">
function test() {
xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200){
var container = document.getElementById('line');
container.innerHTML = xhr.responseText;
} else {
alert(xhr.status);
}
}
xhr.open('GET', 'http://www.google.com', true);
xhr.send(null);
}
</script>
And I always get the alert with the status 0. I've read tons of webs about this and I don't know what am I missing. I will appreciate any help, thanks!
You are running into the Same Origin Policy.
Unless your code is actually running on www.google.com (which is unlikely), this is going to error.
Also, and while this isn't causing you a problem at the moment, it is poor practice and can lead to race conditions, you are using globals all over the place.
Make the xhr variable local to the function
var xhr = new XMLHttpRequest();
And refer to it with this inside the onreadstatechange method.
if (this.readyState == 4 && this.status == 200){
// etc etc
Following from David's answer:
You have to use a relative path to stay within the same origin policy. Otherwise most browsers will simply return an empty responseText and status == 0.
As one possible workaround, you could set up a very simple reverse proxy (with mod_proxy if you are using Apache). This would allow you to use relative paths in your AJAX request, while the HTTP server would be acting as a proxy to any "remote" location.
The fundamental configuration directive to set up a reverse proxy in mod_proxy is the ProxyPass. You would typically use it as follows:
ProxyPass /ajax/ http://google.com/
In this case, the browser would be requesting /ajax/search?q=stack+overflow but the server would serve this by acting as a proxy to http://google.com/search?q=stack+overflow.
In addition to the same origin policy issue, your alert is in an illogical place. When you use XMLHttpRequest, the function assigned to xhr.onreadystatechange will be called whenever readyState changes. readyState should change (in theory) from 0 (initialized) to 1 (sent) to 2 (loading) to 3 (interactive) to 4 (finished).
What your code does is check the readyState and see if the request is finished (if (xhr.readyState == 4)), and if not, alert the HTTP status code. Since the request hasn't been sent yet (or has just been sent), there shouldn't be an HTTP status yet.
Ideally, you should move the alert inside the if block, so it lets you know when it finishes.
I have a web app driven by a servlet that times out users' sessions after a period of inactivity by redirecting to a login page. I had code in place on the web client that checked for this, essentially similar to the following:
function error(request, errtype) {
if (request.status == 302) {
// Display a "timed out" dialog, then:
window.location = request.getResponseHeader("Location");
}
}
However, recently this scheme stopped working; on timeout, the request.status was 0. Using Firebug I could see that the same HTTP 302 response was being returned.
I read the spec for XMLHttpRequest carefully, and found this section:
If the redirect does not violate security (it is same origin for instance), infinite loop precautions, and the scheme is supported, transparently follow the redirect while observing the same-origin request event rules.
Otherwise, this is a network error.
I hadn't even known that clients were supposed to automatically follow redirects that they get in response to Ajax requests; the browsers I care about didn't do that before, since my code above used to work. I recently upgraded my version of Firefox, which now perhaps is following the spec more closely. The network error prescribed by the spec would explain the zero response code I'm seeing. However, the redirect I'm getting is to the same host (albeit on a different port), there shouldn't be an infinite loop, and the scheme remains HTTP, so I don't understand why I'm getting a network error.
Any ideas?
how you are you getting to this function? if you're only sending it to "error" on a 200 status obviously this wouldn't work...
request.onreadystatechange = function( )
{
if( this.readyState == 4 )
{
// if we got a 200
if( this.status == 200 ){ /* cool */ }
// if we got anything else
else { error( this, this.status ); }
}
};
But I'm assuming you know this. Also, you should probably include .href at the end of window.location and possibly a default location just in case
// Display a "timed out" dialog, then:
window.location.href = request.getResponseHeader("Location") || defaultPage;
If this doesn't work, you might wanna try a different status in the onreadystatechange method, as some browsers may interpret a non 200 status as an error. These could be (from that same spec you're reading from):
0 (if it's considered aborted after unset, though unlikely)
2 (headers-sent) as that 302 code is actually a HTTP header
good luck!