Multiple HTTP Request to a Single File - javascript

Currently, I am attempting to call a single PHP file named 'sniffer.php'.
I am doing this async using javascript to a PHP file. The issue that I am currently having is that in the PHP code I added a sleep function to randomly (to act like a page is loading). The issue with that is two or more functions call that page it still waits until one of the pages finishes first then stops starts the other request. EG: One sleeps for 5 seconds and the other sleeps for 6 seconds. The first one completes in 5 seconds and the next one finishes at 11 seconds. What I am looking for is the one finishes in 5 seconds and the next finishes the one second after. I am not sure if it's just 'sleep' causing the issue or if the file is 'locked' because of the sleep.
Thanks for any help/feedback.
My PHP File looks like this:
$c = rand(2,10);
sleep($c);
$html .= $c;
echo json_encode(array('html'=>$html,'status'=>1));
exit;
My javascript class looks like this:
var path = '/';
var polling = {
add : function(name, obj) {
this[name] = new xAjax(obj);
return this;
}
};
function xAjax(options) {
var consti = {
};
var defaults = {
url: path + 'sniffer.php',
method: 'POST',
responseType: 'json',
async: true,
timeout: 30000,
success: function(response) {console.log(response);},
done: function() {},
beforeSend: function() {},
error: function(e) {console.log(e);},
abort: function() {}
};
var settings = Object.assign({}, defaults, options, consti);
var xhr = null;
this.run = function() {
xhr = new XMLHttpRequest();
settings.beforeSend();
xhr.responseType = settings.responseType;
xhr.open(settings.method, settings.url, settings.async);
xhr.timeout = settings.timeout;
xhr.onreadystatechange = function() {
if ( xhr.readyState == XMLHttpRequest.DONE ) {
if ( xhr.status === 200 ) {
settings.success(xhr.response);
} else {
settings.error(xhr.response);
}
settings.done();
xhr = null;
}
};
xhr.send();
return this;
};
this.abort = function() {
xhr.abort();
xhr = null;
settings.abort();
return this;
};
this.isRunning = function() {
return xhr != null;
};
this.set = function(options) {
settings = Object.assign({}, defaults, options, consti);
return this;
};
}
My creation/call to the sniffer.php:
polling.add('x');
polling.x.run();
polling.add('y');
polling.y.run();

This is happening because of sessions. It would happen with or without sleep, if the script takes time.
What happens when you start a session? PHP has to make sure the session data is current and that it will not change, it also has to make sure that the data it changes will be available in the next executions.
So if a script tries to open the session while it is open somewhere else, there's a lock, because the first script might very well change the session information still. Once the first script closes the session, the next script can get a hold of it and go on.
You can call session_write_close() to close the session for write, and thus remove the lock. While the session is closed, its value can still be accessed but it will be the value before any subsequent script changed anything (if your second script changes something before first script ends, it will not be known). Also, if you write new data to the session, it will not be saved...
From documentation
Session data is usually stored after your script terminated without
the need to call session_write_close(), but as session data is locked
to prevent concurrent writes only one script may operate on a session
at any time.
Also it seems like you are not the only one:
You can have interesting fun debugging anything with sleep() in it if
you have a session still active. For example, a page that makes an
ajax request, where the ajax request polls a server-side event (and
may not return immediately).
If the ajax function doesn't do session_write_close(), then your outer
page will appear to hang, and opening other pages in new tabs will
also stall.

Related

JavaScript - How to send multiple XMLHttp requests or force the XMLHTTP request to wait till I get the desired response?

I am making a GET request to the api using XMLHttpRequests. The api takes in a "uuid" value denoted by the variable "a" here as a parameter, uses that value for processing and is supposed to spit out some information that I am trying to print to the console.
However, the problem I am running into is that, whenever the api successfully receives the uuid value it returns a message where the newresponse.response.status is Initiated. However I want to wait till the newresponse.response.status is Success (this usually takes a short bit like 3-4 seconds more).
The original code is shown below:
function getrequestresults(status, response) {
let parse = JSON.parse(response);
let a = parse.uuid;
let newrequest = new XMLHttpRequest();
newrequest.open('GET', "http://localhost:5000/api/v1/dags/results" + "?" + "uuid" + "=" + a, true);
newrequest.onload = function() {
//console.log(newrequest.status);
console.log(newrequest.response);
};
newrequest.send();
}
One of the attempts I made at fixing this was as follows:
function getrequestresults(status, response) {
let parse = JSON.parse(response);
let a = parse.uuid;
let newrequest = new XMLHttpRequest();
newrequest.open('GET', "http://localhost:5000/api/v1/dags/results" + "?" + "uuid" + "=" + a, true);
newrequest.onload = function() {
while (newrequest.response.status != "Success") {
//the following line was just to see what's going on, idea was to keep looping till, desired status is reached
console.log(newrequest.response);
}
//console.log(newrequest.status);
console.log(newrequest.response);
};
newrequest.send();
}
However, this did not work as it seems that the "onload" function only runs once, whereas I need it to run multiple times until newrequest.response.status is Success.
I am quite new with sending XMLHttpRequests and some help would be appreciated. Thanks.

asynchronous xhr request within setInterval not working | Javascript

I'm building a tracking library to send events to the backend. An event should be created every 5 seconds (configurable) and sent into the tracking queue, and the tracking queue should be sent to the backend and emptied every 5 seconds (also configurable). The expected behaviour is that an event should be sent to the backend every 5 seconds.
When I was just console.logging the events, everything was working as expected, but when I implemented the xhr request, the interval events were only created every 9 seconds or so. So an event would be sent to the backend, only once every two times the 'post' function fired.
sendData: function(){
var toSend = [].concat(Tracking.__tracking_queue);
if(toSend.length !== 0){
var sendData = this.__stringifyAndSetHeaders(toSend);
Tracking.postData(sendData);
}
},
postData: function(sendData){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.responseText);
Tracking.__tracking_queue = [];
};
xhr.open("POST", sendData.url, true);
Object.keys(sendData.headers).forEach(function(key){
xhr.setRequestHeader([key], sendData.headers[key]);
});
xhr.send(sendData.body);
}
The backend is receiving the data, but not at the correct times. sendData is being called from within a setInterval loop.
setInterval(function(){
self.sendData()
}, 5000);
I had the same setup working perfectly before, in another file using axios, but I cannot use axios in this use-case.
You are resetting the tracking data at the wrong location. You read the data, than make a request, after the request is done, you delete the data. There is a period of time where data can come into the queue between the request and when it finishes.
sendData: function(){
var toSend = [].concat(Tracking.__tracking_queue);
if(toSend.length !== 0){
var sendData = this.__stringifyAndSetHeaders(toSend);
Tracking.__tracking_queue = []; //clear it here
Tracking.postData(sendData);
}
},
postData: function(sendData){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.responseText);
//Tracking.__tracking_queue = []; //don't clear it here
};
xhr.open("POST", sendData.url, true);
Object.keys(sendData.headers).forEach(function(key){
xhr.setRequestHeader([key], sendData.headers[key]);
});
xhr.send(sendData.body);
}

Ajax abort doesn't abort on click, and duplicate request

I have a simple chat done with long polling. The chat has 2 rows of conversations (or more). Each row has a unique id and a number of messages to show.
When I click on the first line, to show the messages of this conversation, I start an ajax, and it keeps persisting inside a loop in the serverside. However, when I click on the second line, I need to end the previous ajax and start a new one.
I tried some options like the ones below, but I did not find a solution.
$('li.chat-conversation').on('click', function(){
var requestRunning = true;
var xhr;
var id = $(this).attr('data-conversation-id');
var ajaxOpt = {...};
var fn = function(){
xhr = $.ajax(ajaxOpt);
if(requestRunning){
xhr.abort();
requestRunning = false;
}
};
var interval = setInterval(fn, 2000);
});
Can anyone help me figure out a logic for this?
Note: setInterval is for example only.
Move xhr outside of click handler scope and check if it exists on click event:
var xhr = null;
$('li.chat-conversation').on('click', function() {
var id = $(this).data('conversation-id');
var ajaxOpt = {...};
// when ajax request finished (does not matter success or failed)
ajaxOpt.complete = function() {
xhr = null;
};
if(xhr) {
xhr.abort();
}
xhr = $.ajax(ajaxOpt);
});
P.S. Extend my example Yourself (:
It turns out that the server response is inserted into a div by "append". And when I click on another conversation, they are running 2
ajax at the same time. And the div is changing content, that is, in a
request, append the messages of the first conversation and in the
other request, append the messages of the second conversation.
Just check the xhr.readystate value and if it isn't 4, abort the request and clear out the conversation related to that request.
Keeping track of active requests with your own Boolean flag can easily get out of sync with multiple requests if you are not setting the flag in all the right places. But the readystate property makes it so we don't have to manage any of that.
Also, you may need to cancel your interval timer when you cancel the AJAX request.
$('li.chat-conversation').on('click', function(){
var xhr = null;
var id = $(this).attr('data-conversation-id');
var ajaxOpt = {...};
var fn = function(){
xhr = $.ajax(ajaxOpt);
// Just check the readystate and if it's not 4 (DONE),
// then cancel the current request.
if(xhr.readystate !== 4){
// Cancel the previous AJAX call(s)
xhr.abort();
// Clear out the conversation related to the request
yourConversationDiv.textContent = "";
} else if(xhr.readystate === 4 && xhr.status === 200){
// Successful result, append to existing conversation
yourConversationDiv.append(xhr.responseText);
}
};
});

Catch Facebook Access token on demand, but how?

I build a Firefox Extension and i'm using the graph api. At the moment i catch the access token of each user while starting the browser like:
https://stackoverflow.com/questions/10301146/facebook-login-within-a-firefox-add-on
This works fine but kind of stupid, because nobody will use the extension in each firefox session. So what i'm trying to do is, catch the access token or more accurately call the methode Wladimir Palant recommends on demand. My code looks like this, while getAccessToken() is the mentioned method.
onLoad: function (){
var NoteHandler = window.arguments[0];
var sjcl = NoteHandler.sjcl;
NoteHandler.getAccessToken();
decryptionDialog.noteHandler = NoteHandler;
decryptionDialog.sjcl = sjcl;
var currID = decryptionDialog.getID();
if(currID==""){
window.close();
return false;
}else{
http_request = new XMLHttpRequest();
http_request.open('Get', 'https://graph.facebook.com/'+currID+'/notes?access_token='+NoteHandler.token, false);
http_request.overrideMimeType("text/json");
http_request.send(null);
decryptionDialog.value = decryptionDialog.ResponseToArray(http_request.responseText);
....
But the problem is while getAccessToken() is still waiting for the access token, the onLoad()-Method won't wait and goes on. Therefore the NoteHandler.token is null while the request is send. Does anyone have an idea, because i'm relatively new to javascript.
You should rewrite this code to be asynchronous - it shouldn't assume that getAccessToken() will get the result immediately, there should be rather a callback parameter, a function to be called when the operation is done (can be a closure function). Something along these lines:
onLoad: function (){
var NoteHandler = window.arguments[0];
var sjcl = NoteHandler.sjcl;
NoteHandler.getAccessToken(function()
{
decryptionDialog.noteHandler = NoteHandler;
decryptionDialog.sjcl = sjcl;
...
http_request.open('Get', 'https://graph.facebook.com/'+currID+'/notes?access_token='+NoteHandler.token, false);
...
});
}
...
getAccessToken: function(callback) {
...
// All done - call the callback
callback();
}

How do I check if file exists in jQuery or pure JavaScript?

How do I check if a file on my server exists in jQuery or pure JavaScript?
With jQuery:
$.ajax({
url:'http://www.example.com/somefile.ext',
type:'HEAD',
error: function()
{
//file not exists
},
success: function()
{
//file exists
}
});
EDIT:
Here is the code for checking 404 status, without using jQuery
function UrlExists(url)
{
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
Small changes and it could check for status HTTP status code 200 (success), instead.
EDIT 2: Since sync XMLHttpRequest is deprecated, you can add a utility method like this to do it async:
function executeIfFileExist(src, callback) {
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (this.readyState === this.DONE) {
callback()
}
}
xhr.open('HEAD', src)
}
A similar and more up-to-date approach.
$.get(url)
.done(function() {
// exists code
}).fail(function() {
// not exists code
})
This works for me:
function ImageExist(url)
{
var img = new Image();
img.src = url;
return img.height != 0;
}
i used this script to add alternative image
function imgError()
{
alert('The image could not be loaded.');
}
HTML:
<img src="image.gif" onerror="imgError()" />
http://wap.w3schools.com/jsref/event_onerror.asp
So long as you're testing files on the same domain this should work:
function fileExists(url) {
if(url){
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.send();
return req.status==200;
} else {
return false;
}
}
Please note, this example is using a GET request, which besides getting the headers (all you need to check weather the file exists) gets the whole file.
If the file is big enough this method can take a while to complete.
The better way to do this would be changing this line: req.open('GET', url, false); to req.open('HEAD', url, false);
Here's how to do it ES7 way, if you're using Babel transpiler or Typescript 2:
async function isUrlFound(url) {
try {
const response = await fetch(url, {
method: 'HEAD',
cache: 'no-cache'
});
return response.status === 200;
} catch(error) {
// console.log(error);
return false;
}
}
Then inside your other async scope, you can easily check whether url exist:
const isValidUrl = await isUrlFound('http://www.example.com/somefile.ext');
console.log(isValidUrl); // true || false
I was getting a cross domain permissions issue when trying to run the answer to this question so I went with:
function UrlExists(url) {
$('<img src="'+ url +'">').load(function() {
return true;
}).bind('error', function() {
return false;
});
}
It seems to work great, hope this helps someone!
All the other answers can fail due to cache!
Making a HTTP request to a file on server can be intercepted with HTTP cache and the cached response is then returned. But the file may be deleted on the server in the meantime, so ignoring cache may return false positive results.
Proper solution would be to create non-cached HTTP HEAD request. Nik Sumeiko's answer uses no-cache header which means that the response can be cached, but must be revalidated before reuse. In this case the server may return 304: Not Modified, which is not 200: OK and thus false negative.
To avoid cache, the correct header is Cache-Control: no-store
File can exist without HTTP 200 response
You should also keep in mind that redirection (301: Moved Permanently, 307: Temporary Redirect or 308: Permanent Redirect) may occur, so the file can exist elsewhere and may be returned from different location: depending on the use-case, one may choose to follow redirection instead of returning false in this case.
Also keep in mind that background requests will be blocked if you check file existence on different domain and its CORS policy is not opened to your server. In this case 403: Forbidden is usually returned, which doesn't mean file does not exist but file is unavailable. Last but not least, the same applies to 500: Internal Server Error response, which means that the HTTP server failed to handle the request, but the file can be available otherwise, like by FTP.
The following code will return true if the file exists, false if not or undefined if the file is unavailable or redirected:
const fileExists = file =>
fetch(file, {method: 'HEAD', cache: 'no-store'})
.then(response => ({200: true, 404: false})[response.status])
.catch(exception => undefined);
fileExists("yourFile.html").then(yes => yes && alert("yourFile.html exists"));
// or in the async scope...
let yourFileExists = await fileExists("yourFile.html");
if(yourFileExists) console.log("It is there!")
else if(yourFileExists===false) console.log("Nope, it was deleted.");
else console.log("You are not worthy the answer, puny human!");
Modern and obsolete approaches
Since we live in the future now, I would also recommend:
$.ajax() obsolete, don't use in new projects
XMLHttpRequest() obsolete, don't use in new projects
fetch() modern approach, use it if you are free to choose
Note GET/POST methods (like <img src...>) are not appropriate here as they waste network traffic by downloading the file (imagine the worst scenario with high resolution photo and user with paid mobile data in area with poor connectivity)
Note Modern PWA approach is to use Cache API with serviceWorker's fetch event which intercepts the communication between the client and HTTP cache. In the example in the link, there should be something like
if(event.request.cache=="no-store") {
// avoid cache storage and pass the request in the chain
// client - cache storage - HTTP cache - server
return fetch(event.request);
}
Without this, the cache settings may be ignored and there may be no way to detect the remote file existence from the main thread with the serviceWorker running - illustrated
here.
JavaScript function to check if a file exists:
function doesFileExist(urlToFile)
{
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
if (xhr.status == "404") {
console.log("File doesn't exist");
return false;
} else {
console.log("File exists");
return true;
}
}
I use this script to check if a file exists (also it handles the cross origin issue):
$.ajax(url, {
method: 'GET',
dataType: 'jsonp'
})
.done(function(response) {
// exists code
}).fail(function(response) {
// doesnt exist
})
Note that the following syntax error is thrown when the file being checked doesn't contain JSON.
Uncaught SyntaxError: Unexpected token <
For a client computer this can be achieved by:
try
{
var myObject, f;
myObject = new ActiveXObject("Scripting.FileSystemObject");
f = myObject.GetFile("C:\\img.txt");
f.Move("E:\\jarvis\\Images\\");
}
catch(err)
{
alert("file does not exist")
}
This is my program to transfer a file to a specific location and shows alert if it does not exist
An async call to see if a file exists is the better approach, because it doesn't degrade the user experience by waiting for a response from the server. If you make a call to .open with the third parameter set to false (as in many examples above, for example http.open('HEAD', url, false); ), this is a synchronous call, and you get a warning in the browser console.
A better approach is:
function fetchStatus( address ) {
var client = new XMLHttpRequest();
client.onload = function() {
// in case of network errors this might not give reliable results
returnStatus( this.status );
}
client.open( "HEAD", address, true );
client.send();
}
function returnStatus( status ) {
if ( status === 200 ) {
console.log( 'file exists!' );
}
else {
console.log( 'file does not exist! status: ' + status );
}
}
source: https://xhr.spec.whatwg.org/
This is an adaptation to the accepted answer, but I couldn't get what I needed from the answer, and had to test this worked as it was a hunch, so i'm putting my solution up here.
We needed to verify a local file existed, and only allow the file (a PDF) to open if it existed. If you omit the URL of the website, the browser will automatically determine the host name - making it work in localhost and on the server:
$.ajax({
url: 'YourFolderOnWebsite/' + SomeDynamicVariable + '.pdf',
type: 'HEAD',
error: function () {
//file not exists
alert('PDF does not exist');
},
success: function () {
//file exists
window.open('YourFolderOnWebsite/' + SomeDynamicVariable + '.pdf', "_blank", "fullscreen=yes");
}
});
First creates the function
$.UrlExists = function(url) {
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
After using the function as follows
if($.UrlExists("urlimg")){
foto = "img1.jpg";
}else{
foto = "img2.jpg";
}
$('<img>').attr('src',foto);
Here's my working Async Pure Javascript from 2020
function testFileExists(src, successFunc, failFunc) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState === this.DONE) {
if (xhr.status === 200) {
successFunc(xhr);
} else {
failFunc(xhr);
}
}
}
// xhr.error = function() {
// failFunc(xhr);
// }
// xhr.onabort = function() {
// failFunc(xhr);
// }
// xhr.timeout = function() {
// failFunc(xhr);
// }
xhr.timeout = 5000; // TIMEOUT SET TO PREFERENCE (5 SEC)
xhr.open('HEAD', src, true);
xhr.send(null); // VERY IMPORTANT
}
function fileExists(xhr) {
alert("File exists !! Yay !!");
}
function fileNotFound(xhr) {
alert("Cannot find the file, bummer");
}
testFileExists("test.html", fileExists, fileNotFound);
I could not force it to come back with any of the abort, error, or timeout callbacks.
Each one of these returned a main status code of 0, in the test above, so
I removed them. You can experiment.
I set the timeout to 5 seconds as the default seems to be very excessive.
With the Async call, it doesn't seem to do anything without the send() command.
What you'd have to do is send a request to the server for it to do the check, and then send back the result to you.
What type of server are you trying to communicate with? You may need to write a small service to respond to the request.
This doesn't address the OP's question, but for anyone who is returning results from a database: here's a simple method I used.
If the user didn't upload an avatar the avatar field would be NULL, so I'd insert a default avatar image from the img directory.
function getAvatar(avatar) {
if(avatar == null) {
return '/img/avatar.jpg';
} else {
return '/avi/' + avatar;
}
}
then
<img src="' + getAvatar(data.user.avatar) + '" alt="">
It works for me, use iframe to ignore browsers show GET error message
var imgFrame = $('<iframe><img src="' + path + '" /></iframe>');
if ($(imgFrame).find('img').attr('width') > 0) {
// do something
} else {
// do something
}
I wanted a function that would return a boolean, I encountered problems related to closure and asynchronicity. I solved this way:
checkFileExistence= function (file){
result=false;
jQuery.ajaxSetup({async:false});
$.get(file)
.done(function() {
result=true;
})
.fail(function() {
result=false;
})
jQuery.ajaxSetup({async:true});
return(result);
},

Categories

Resources