How to check XMLHttpPRequest 's unique ID? - javascript

I am trying to complete my website request Tamper tool written in JavaScript, However, I am facing my last issue. Below is example function to hook to XMLHttpRequest request. Each request immediately starts with readyState=1, however, only after server returns response, it gets readyState=4.
https://jsfiddle.net/v4mgna51/
However, my problem is that, once in every 1 second, the request is fired, and before it gets response from server, another request might have started in the meanwhile, so making me unable to track (inside readyState==4 ) to check to which initiated call does this "response" corresponds to.
How can I find that out?

The only way I saw was a bit ugly approach (adding uniqueID manually), like this:
this.addEventListener("readystatechange", function(event) {
if(this.readyState == 1){
event.target.uniqueID = Math.floor( (Math.random() * 99999999) + 1 );
}
if(this.readyState == 4){
console.log(event.target.uniqueID);
}
}, false);

Related

Spark POST returns 404 not found seemingly-arbitrarily

Spark has been acting weird lately. I have a button which when clicked calls a POST method with some query parameters:
post("/test", (request, response) -> {
model.put("reason", "some reason here");
...
LOG.info("Returning from /test with reason: " + model.get("reason"));
// the above line always executes and always prints the correct output (never 404)
return new ModelAndView(model, "test.vtl");
}, new VelocityTemplateEngine());
The file test.vtl contains only this: $reason
(which is used in the JS code below to show an alert with the contents of the reason key in the model map).
JS relevant code:
xmlHttp.open("POST", "/test", true);
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var params = "file=" + file + "&searchStr=" + searchStr;
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == XMLHttpRequest.DONE) {
alert(xmlHttp.responseText);
}
}
xmlHttp.send(params);
When I click it, sometimes it work perfectly, and when I click again I get a 404 Not Found with:
MatcherFilter:152 - The requested route [/test] has not been mapped in Spark
This happens in a matter of seconds. I click - it works - I click again if fails - again it fails - again it fails - again it suddenly succeeds...
How can that be?
P.s. I have logging inside the post request, so I know Spark is actually accessing it. But it is not returning from it. Does this perhaps have to do with the code inside the post that suddenly raises the 404 (I am not accessing other pages from it though).
There seem to be 2 possible answers to this (why do they solve is a different question):
Adding a Thread.sleep(250); // or even lower.
Changing the request to GET.
I could not find what is the root cause of these arbitrary failures, but ended up choosing option #2.

Not Receiving Asynchronous AJAX Requests When Sent Rapidly

My script is sending a GET request to a page (http://example.org/getlisting/) and the page, in turn, responds back with a JSON object. ({"success":true, "listingid":"123456"})
Here's an example snippet:
var listingAjax = new XMLHttpRequest();
listingAjax.addEventListener("load", listingCallback, false);
function listingCallback(event) {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
}
listingAjax.open("GET", "http://example.org/getlisting/", true);
listingAjax.send();
Simple enough. The script works perfectly too! The issue arises when I want to do this:
var listingAjax = new XMLHttpRequest();
listingAjax.addEventListener("load", listingCallback, false);
function listingCallback(event) {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
}
window.setInterval(function() {
listingAjax.open("GET", "http://example.org/getlisting/", true);
listingAjax.send();
}, 250);
What I imagine should happen is my script would create a steady flow of GET requests that get sent out to the server and then the server responds to each one. Then, my script will receive the server's responses and send them to the callback.
To be more exact, say I let this script run for 5 seconds and my script sent out 20 GET requests to the server in that time. I would expect that my callback (listingCallback) would be called 20 times as well.
The issue is, it isn't. It almost seems that, if I sent out two GET requests before I received a response from the server, then the response is ignored or discarded.
What am I doing wrong/misunderstanding from this?
Many browsers have a built in maximum number of open HTTP connections per server. You might be hitting that wall?
Here is an example from Mozilla but most browsers should have something like this built in: http://kb.mozillazine.org/Network.http.max-connections-per-server
An earlier question regarding Chrome:
Increasing Google Chrome's max-connections-per-server limit to more than 6
If you have Windows, take a look at a tool like Fiddler - you might be able to see if all of the requests are actually being issued or if the browser is queueing/killing some of them.
You can't reuse the same XMLHttpRequest object opening a new connection while one is in progress, otherwise it will cause an abrupt abortion (tested in Chrome). Using a new XMLHttpRequest object for each call will solve that:
function listingCallback(event) {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
}
window.setInterval(function() {
var listingAjax = new XMLHttpRequest();
listingAjax.addEventListener("load", listingCallback, false);
listingAjax.open("GET", "http://example.org/getlisting/", true);
listingAjax.send();
}, 250);
This will work nicely queueing a new ajax request for each interval.
Fiddle
Note that too frequent calls may cause slowdown due to the maximum limit of concurrent ajax calls which is inherent to each browser.
Though, modern browsers have a pretty fair limit and very good parallelism, so as long as you're fetching just a small JSON object modern browsers should be able to keep up even when using a dial-up.
Last time I made an ajax polling script, I'd start a new request in the success handler of the previous request instead of using an interval, in order to minimize ajax calls. Not sure if this logic is applicable to your app though.

Get if browser is busy

I'm trying to find a way to get if the browser is currently busy from JavaScript. I'm looking at making a Firefox extension to inject a Boolean value or something if the current page is loading something (either through ajax or just normal page loads), or the same with a Greasemonkey script, or through some JavaScript API (this would be the best solution, but from what I can see, nothing of the sort exists).
I was wondering what the best way to do this would be. I've been looking for Firefox Addon / Greasemonkey tutorials for making something like this and can't find anything. Does anyone have any tips or resources they could point me towards or better solutions for solving this?
Thanks
Edit: and by busy, I mostly just need to know if the browser is sending or receiving data from a server.
jQuery, a great javascript framework for DOM manipulation and performing ajax calls, provides two great hooks for determining when ajax calls are in progress:
$.ajaxStart() and $.ajaxStop()
Both of these hooks take a handler function that will be called when an ajax call is about to start, and when all ajax calls have ceased, respectively. These functions can be bound to any element on the page. You could set a global boolean value in your $.ajaxStart() handler to true and set it back to false in your $.ajaxStop() handler.
You could then check that boolean flag and determine whether ajax calls are in progress.
Something along these lines:
$(document).ajaxStart(function() {
window.ajaxBusy = true;
});
$(document).ajaxStop(function() {
window.ajaxBusy = false;
});
As far as determining when the browser is loading the current page, you could check
document.readyState. It returns a string of "loading" while the document is loading and a string of "complete" once it has loaded. You can bind a handler to document.onreadystatechange and set a global boolean that will indicate whether the document is still loading or not.
Something like this:
document.onreadystatechange = function() {
switch (document.readyState) {
case "loading":
window.documentLoading = true;
break;
case "complete":
window.documentLoading = false;
break;
default:
window.documentLoading = false;
}
}
EDIT:
It appears that $.ajaxStart() and $.ajaxStop() do NOT work for ajax calls invoked without jQuery. All XMLhttprequest objects have an event called readystatechange that you can attach a handler to. You could utilize this functionality to determine whether or not that individual call is done. You could push all references to outstanding calls onto an array, and in a setInterval() check that array's length. If it > 1, there are out standing ajax calls. It's a rough approach, and only one way of getting about it. There are probably other ways to do this. But here's the general approach:
// declare array to hold references to outstanding requets
window.orequets = [];
var req = XMLHttpRequest();
// open the request and send it here....
// then attach a handler to `onreadystatechange`
req.onreadystatechange = function() {
if (req.readyState != 4 || req.readyState != 3) {
// req is still in progress
orequests.push(req);
window.reqPos = orequests.length -1
} else {
window.orequests = orequests.slice(reqPos, reqPos + 1);
}
}
Do the above for each XMLHttpRequest() you will be sending, of course changing the request name for each one. Then run a setInterval() that runs every x amount of milliseconds, and checks the length property of orequests. If it is equal to zero, no requests are happening, if it is greater than zero, requests are still happening. If no requests are happening, you can either clear the interval through clearInterval() or keep it running.
Your setInterval might look something like this:
var ajaxInterval = setInterval(function() {
if (orequests.length > 0) {
// ajax calls are in progress
window.xttpBusy = true;
} else {
// ajax calls have ceased
window.xttpBusy = false;
// you could call clearInterval(ajaxInterval) here but I don't know if that's your intention
},
3000 // run every 3 seconds. (You can decide how often you want to run it)
});
Here's what I think I'll end up doing. This solution is like the one Alex suggested with the Jquery events, except that it works with anything that uses the XMLHttpRequest (Including Jquery):
var runningAjaxCount = 0;
var oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
oldOnReady = this.onreadystatechange;
this.onreadystatechange = function() {
oldOnReady.call(this);
if(this.readyState == XMLHttpRequest.DONE) {
ajaxStopped();
}
}
ajaxStarted();
oldSend.apply(this, arguments);
}
function ajaxStarted() {
runningAjaxCount++;
}
function ajaxStopped() {
runningAjaxCount--;
}
function isCallingAjax() {
return runningAjaxCount > 0;
}
function isBrowserBusy() {
return document.readyState != "complete" && isCallingAjax();
}
The browser technically isn't ever "busy". Business is a very subjective term. Let's assume that the main thread is performing a simple while loop which blocks execution. This could be considered busy, but what if you have something like this:
function busy() {setTimeout(busy, 0);do_something();}
busy();
The browser isn't being blocked (per se), so whether or not the page is "busy" is very unclear. Also, that doesn't even begin to touch on web workers and code in the chrome.
You're going to be hard-pressed to do this, and even if you do, it likely won't work how you expect it to. Good luck, nonetheless.

onreadystatechange in a loop, readystate changes too late

I issue in a loop a total of eight xmlhttprequests to a Google map server and process the json objects the server returns to retrieve the zip codes. The code works fine if the xmlhttprequests are synchronous. Since I'm supposed to use asynchronous requests, I'm trying to convert the code to asynchronous. It doesn't work.
I use two alerts to monitor myZip. When the code is run, the second alert, right above the return, runs eight times and shows myZip as null or undefined and that is what is returned. Then the first alert runs eight times and gives the desired zip code, too late, unfortunately. It seems to me the readystate doesn't change until too late.
How should I modify the code so it will return the zip code, not null? Any help will be greatly appreciated.
var url = "http://maps.googleapis.com/maps/api/geocode/json?address="+address+city+state+"&sensor=false";
req.open("GET", url,true);
var myZip;
req.onreadystatechange = function()
{
if(req.readyState == 4 && req.status == 200) {
(function(data){
var myObj = eval( '(' + data + ')' );
if(myObj.status=="OK"){
for(i=0; i <myObj.results[0].address_components.length; i++){
if(myObj.results[0].address_components[i].types=="postal_code"){
myZip=myObj.results[0].address_components[i].long_name;
alert('zip is '+myZip);
}
}
}
else
{
alert("Error: returned status code "+req.status+" "+req.statusText);
}
})(req.responseText);
}
}
req.send();
alert(myZip);
return myZip;
You should either use a callback instead of return statement, or you should run this as Stratified JavaScript: http://stratifiedjs.org.
Then you can write it in a synchronous fashion, like you kind of did, even though it will NOT block your browser.
I guess you use the same object(req) a couple of times and will be overwritten on each loop.
So use separate objects for every requests or start a new request if the last one is finished.
How exactly you can do this I cannot say without knowing what req is.

Ajax call not responding on repeated request

I have a page with a dropdown. The onchange event calls a Javascript function (below) that includes an Ajax block that retrieves data and populates a TEXTAREA. On the surface, everything works.
I can select any item in the list with no problems. However, if I select an item that has previously been selected, the Ajax call appears to hang. It looks like maybe some weird caching issue or something. If I close the browser and reload the page, all items work again until I re-select.
I've tested for the readyState and status properties when it's hanging, but I get nothing. Am I missing something?
The page is a client project behind authentication so I can't post a URL, but here's the Ajax code. This is in a PHP page, but there's no PHP script related to this.
function getText( id ) {
var txt = document.getElementById( "MyText" );
txt.disabled = "disabled";
txt.innerText = "";
txt.className = "busy";
var oRequest = zXmlHttp.createRequest();
oRequest.open( "get", "get_text.php?id=" + id, true );
oRequest.send( null );
oRequest.onreadystatechange = function() {
if( oRequest.readyState == 4 ) {
if( oRequest.status == 200 ) {
txt.innerText = oRequest.responseText;
} else {
txt.innerText = oRequest.status + ": " + oRequest.statusText;
}
txt.disabled = "";
txt.className = "";
oRequest = null;
}
}}
Edit: The code block seems a little quirky; it won't let me include the final } unless it's on the same line as the previous.
You're setting the onreadystatechange function after you're sending the request. If it takes a long time (ie if it goes to the server), this will probably work, since there will be a delay before it tries to call the callback.
If the page is cached, though, the browser is probably trying to call onreadystatechange immediately in the send method. Move your assignment to onreadystatechange to before the open/send code.
HI,
The caching is due to the same url thats being called repeatedly. If you change the URl dynamically then this issue can be rsolved. Something like by adding a querystring with the current time with the request ( or any random renerated number ) you can change the url without affecting the result
I would guess that you are running into a caching issue. I have noticed that Internet Explorer is more aggressive at caching ajax calls than Firefox is. One way to be sure of what is happening is to use Fiddler2. This application monitors your web traffic, and you would be able to see if the browser is making a request or not, and what cache headers are coming back on the responses that you do get.
You can download fiddler2 from http://www.fiddlertool.com/fiddler/

Categories

Resources