Send XHR request without receiving any data - javascript

I'm trying to make a very simple script that should keep me logged on a site, that deletes your session after 10 minutes of inactivity. This is quite simple, as follows:
//Silently "refresh" the page - at least server thinks you refreshed, thus you're active
function call() {
var req = new XMLHttpRequest();
//Load current url
req.open("GET",location.href,true);
//Try to only send the data! (does not work - the browser also receives data)
req.onprogress = function() {
this.abort(); //Abort request
wait(); //Wait another 5 minutes
}
//Repeat request instantly if it fails
req.onerror = call;
//Send
req.send();
}
function wait() {
//5minutes timeout
setTimeout(call,5000);
}
wait();
This works perfectly but the requests seem to load completely. Though the page is small, I want to make this clean and prevent downloading the data. This means, I want to stop loading just after the data starts downloading. Or better - after the data has been sent.
Is there a way to make such "ping" function?

I tried this code:
var req = new XMLHttpRequest();
req.onreadystatechange = function(){
console.log( this.readyState );
if( this.readyState == 2 ) { //sent, otherwise it raises an error
console.log( 'aborting...' );
this.abort()
}
if( this.readyState == 4 ) {
console.log( this.responseText );
}
}
req.open( 'get', .... );
req.send();
prints:
1
2
aborting...
3
4
undefined
I am not completely sure with this, but I guess that by aborting the request aborts the download and retrieval of data, but all other states are triggered. I try this with a large image which was not cached and the request was done very quickly, without any result.
BTW. To just send a »ping« to your server you can also set the src of an image tag to the desired script, this will trigger the request too.

Related

Ajax Post to a different domain url , redirect to another url

I am supposed to call a third party vendor - Cybersource using their silent order post. The problem is that I have an accordion page which has 3 panes, Account creation, Service address and billing (on third pane).
I am trying make an ajax call from [http://mydomain/billing][1] TO [http://cybersource/silentorderpost/pay][1].
In the post parameters I am setting response url = [http://mydomain/billing][1] this is where CS will send the response back.
When the Ajax post goes from my website to CS website, I do not get a callback but the Cybersource post the response back to my website [http://mydomain/billing][1] and this reloads my whole accordion page which I am trying to avoid. I understand that During an Ajax call, the Ajax expects a response on the same domain as "Called webservice", i.e. my Ajax post expects that Cybersource will post the response on something like [http://cybersource/response][1]. However, CS posts or redirects the response to my website and this is probably the reason, I never get my callback. When the response is posted my whole accordion page reloads and this causes all sorts of issues.
My Code:
function myFunction() {
//document.getElementById("myForm1").submit();
var http= new XMLHttpRequest();
var url = "https://testsecureacceptance.cybersource.com/silent/pay";
var params = document.getElementById("queryStr");
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.send(params);
//Send the proper header information along with the request
http.onreadystatechange = function() {//IT NEVER COMES BACK TO THIS SECTION
if(http.readyState == 4) {
alert(http.responseText);
console.log("I came back");
}
}
}
</script>
USING JQUERY:
function myFunction() {
//document.getElementById("myForm1").submit();
var http= new XMLHttpRequest();
var url = "https://testsecureacceptance.cybersource.com/silent/pay";
var params = document.getElementById("queryStr");
var jqxhr = $.post( url, function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
// Set another completion function for the request above
jqxhr.always(function() {
alert( "second finished" );
});
}
Any solutions?
var xhr = new XMLHttpRequest();
xhr.open('POST',url,true);
var params = document.getElementById("queryStr");
// you need to call this method:
xhr.send(params);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
//return stuff
} else {
//return stuff
}
}
just like i wrote in my comment, you also need to send your request to the server via xmlhttprequestObject.send() before the readystate can change.
greetings
I found a way out. On my form I added an iframe and now when I get a post response from CS, my page does not reload, instead the response is updated in the iframe.
<form action="https://testsecureacceptance.cybersource.com/silent/pay" method ="post" target="myIframe"> ..... </form>
<iframe src="" name="myIframe"></iframe>
I got the same issue when I integrate cyber source silent post order. I resolved it with form with hidden input fields to create the signature and invisible iframe as the target for my form.
Few things you need to take care while integrating cyber source silent post
1. Make sure you are passing all required fields
2.Generate unique application number and uuid otherwise cyber source will consider it as duplicate request
3.create the signature to make sure input fields are not tampered
4.Dont use ajax to submit the request, in this case the call might ge success but cyber source will not call your customer post back URL that you configured for response.

difference between youtube's request and mine

i want to make a script that makes every video's comment section look like the ones that still have the old kind.
for example, videos on this channel:https://www.youtube.com/user/TheMysteryofGF/videos
in Firebug, in the Net tab, i noticed the comment JSON file's URL it is requested from is different.
i tried to run a code on the youtube watch page which would request the file the same way, but it doesnt work, and in firebug it says it was forbidden.
the URL is the same, they are both POST, and i cant figure out what is different. i can even resend the original request in firebug and it works... so anyway, here is a code i tried on a video with "1vptNpkysBQ" video url.
var getJSON = function(url, successHandler, errorHandler) {
var xhr = typeof XMLHttpRequest != 'undefined'
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('post', url, true);
xhr.onreadystatechange = function() {
var status;
var data;
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
if (xhr.readyState == 4) { // `DONE`
status = xhr.status;
if (status == 200) {
data = JSON.parse(xhr.responseText);
successHandler && successHandler(data);
} else {
errorHandler && errorHandler(status);
}
}
};
xhr.send();
};
getJSON('https://www.youtube.com/watch_fragments_ajax?v=1vptNpkysBQ&tr=time&frags=comments&spf=load', function(data) {
alert('Your public IP address is: ' + data);
}, function(status) {
alert('Something went wrong.');
});
You are using Ajax to get data. Ajax has 1 restriction: You can only get data from your own server. When you try to get data from another server/domain, you get a "Access-Control-Allow-Origin" error.
Any time you put http:// (or https://) in the url, you get this error.
You'll have to do it the Youtube way.
That's why they made the javascript API. Here is (the principal of) how it works. You can link javascript files from other servers, with the < script > tag
So if you could find a javascript file that starts with
var my_videos = ['foo', 'bar', 'hello', 'world'];
then you can use var my_videos anywhere in your script. This can be used both for functions and for data. So the server puts this (dynamically generated) script somewhere, on a specific url. You, the client website can use it.
If you want to really understand it, you should try building your own API; you'll learn a lot.
Secondary thing: Use GET.
POST means the client adds data to the server (example: post a comment, upload a file, ...). GET means you send some kind of ID to the server, then the server returns its own data to the client.
So what you are doing here, is pure GET.

why do we use setTimout function if AJAX is asynchronous?

I have been using jquery libraries for implementing AJAX. it was ok and I am comfortable with that. However, I started reading some ajax book and found the following code.
// stores the reference to the XMLHttpRequest object
var xmlHttp = createXmlHttpRequestObject();
// retrieves the XMLHttpRequest object
function createXmlHttpRequestObject()
{
// will store the reference to the XMLHttpRequest object
var xmlHttp;
// if running Internet Explorer
if(window.ActiveXObject)
{
try
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
xmlHttp = false;
}
}// if running Mozilla or other browsers
else
{
try
{
xmlHttp = new XMLHttpRequest();
}
catch (e)
{
xmlHttp = false;
}
}
// return the created object or display an error message
if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;
}
// make asynchronous HTTP request using the XMLHttpRequest object
function process()
{
// proceed only if the xmlHttp object isn't busy
if (xmlHttp.readyState == 4 || xmlHttp.readyState == 0)
{
// retrieve the name typed by the user on the form
name = encodeURIComponent(document.getElementById("myName").value);
// execute the quickstart.php page from the server
xmlHttp.open("GET", "quickstart.php?name=" + name, true);
// define the method to handle server responses
xmlHttp.onreadystatechange = handleServerResponse;
// make the server request
xmlHttp.send(null);
}
else
// if the connection is busy, try again after one second
setTimeout('process()', 1000);
}
//executed automatically when a message is received from the server
function handleServerResponse()
{
// move forward only if the transaction has completed
if (xmlHttp.readyState == 4)
{
// status of 200 indicates the transaction completed successfully
if (xmlHttp.status == 200)
{
// extract the XML retrieved from the server
xmlResponse = xmlHttp.responseXML;
// obtain the document element (the root element) of the XML structure
xmlDocumentElement = xmlResponse.documentElement;
// get the text message, which is in the first child of
// the the document element
helloMessage = xmlDocumentElement.firstChild.data;
// update the client display using the data received from the server
document.getElementById("divMessage").innerHTML =
'<i>' + helloMessage + '</i>';
// restart sequence
setTimeout('process()', 1000);
}
// a HTTP status different than 200 signals an error
else
{
alert("There was a problem accessing the server: " + xmlHttp.statusText);
}
}
}
Here my question is why do we use setTimeout('process()', 1000); in handleServerResponse() function? Can't we do this without setTimeout('process()', 1000);?
For me, it looks like some kind of constant polling. It's reusing the AJAX request over and over every second, and when the previous request is still active, it waits another second to send it again. So it's not just create an AJAX request and deal with the response.
Using that code, the page would be updating constantly with the information retrieved from the server. Whenever server response has changed, page will as well but not in real time (only when next request finishes). It's similar to Periodic Refresh.
As an evolution, you can have Long Polling in which you spawn an AJAX request and then wait until server responds. If any info is there in the server for you, you'll receive the response immediately. If, while you are waiting for response, anything comes to the server for you, you will receive it. If your request times out, server will respond with an empty body. Then, your client will spawn another AJAX request. You can get some more info from the Wikipedia. Extra link: Comet.
In the given example , the book has call the process() function on the body onload event.
When I change the code to onload-> to onkeyup <input type="text" id="myName" onkeyup="process()"/> I could remove the code //setTimeout('process()', 1000);

using javascript to detect whether the url exists before display in iframe

I'm using javascript to pass a dynamic url to iframe src. but sometimes the url does not exist, how could i detect the non-exist url beforehand, so that i can hide the iframe that with 404 error.
Due to my low reputation I couldn't comment on Derek 朕會功夫's answer.
I've tried that code as it is and it didn't work well. There are three issues on Derek 朕會功夫's code.
The first is that the time to async send the request and change its property 'status' is slower than to execute the next expression - if(request.status === "404"). So the request.status will eventually, due to internet band, remain on status 0 (zero), and it won't achieve the code right below if. To fix that is easy: change 'true' to 'false' on method open of the ajax request. This will cause a brief (or not so) block on your code (due to synchronous call), but will change the status of the request before reaching the test on if.
The second is that the status is an integer. Using '===' javascript comparison operator you're trying to compare if the left side object is identical to one on the right side. To make this work there are two ways:
Remove the quotes that surrounds 404, making it an integer;
Use the javascript's operator '==' so you will be testing if the two objects are similar.
The third is that the object XMLHttpRequest only works on newer browsers (Firefox, Chrome and IE7+). If you want that snippet to work on all browsers you have to do in the way W3Schools suggests: w3schools ajax
The code that really worked for me was:
var request;
if(window.XMLHttpRequest)
request = new XMLHttpRequest();
else
request = new ActiveXObject("Microsoft.XMLHTTP");
request.open('GET', 'http://www.mozilla.org', false);
request.send(); // there will be a 'pause' here until the response to come.
// the object request will be actually modified
if (request.status === 404) {
alert("The page you are trying to reach is not available.");
}
Use a XHR and see if it responds you a 404 or not.
var request = new XMLHttpRequest();
request.open('GET', 'http://www.mozilla.org', true);
request.onreadystatechange = function(){
if (request.readyState === 4){
if (request.status === 404) {
alert("Oh no, it does not exist!");
}
}
};
request.send();
But notice that it will only work on the same origin. For another host, you will have to use a server-side language to do that, which you will have to figure it out by yourself.
I found this worked in my scenario.
The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callback methods introduced in jQuery 1.5 are deprecated as of jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.
$.get("urlToCheck.com").done(function () {
alert("success");
}).fail(function () {
alert("failed.");
});
I created this method, it is ideal because it aborts the connection without downloading it in its entirety, ideal for checking if videos or large images exist, decreasing the response time and the need to download the entire file
// if-url-exist.js v1
function ifUrlExist(url, callback) {
let request = new XMLHttpRequest;
request.open('GET', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('Accept', '*/*');
request.onprogress = function(event) {
let status = event.target.status;
let statusFirstNumber = (status).toString()[0];
switch (statusFirstNumber) {
case '2':
request.abort();
return callback(true);
default:
request.abort();
return callback(false);
};
};
request.send('');
};
Example of use:
ifUrlExist(url, function(exists) {
console.log(exists);
});
You could test the url via AJAX and read the status code - that is if the URL is in the same domain.
If it's a remote domain, you could have a server script on your own domain check out a remote URL.
Using async/await, this worked for me for opening a new tab; I needed to detect a 404 for the same reason as the OP:
openHelp : async function(iPossiblyBogusURL) {
const defaultURL = `http://guaranteedToWork.xyz`;
const response = await fetch(iPossiblyBogusURL);
if (response.status == 200) {
window.open(iPossiblyBogusURL, `_blank`);
} else if (response.status === 404) {
window.open(defaultURL, `_blank`);
}
},
You can try and do a simple GET on the page, if you get a 200 back it means the page exists. Try this (using jQuery), the function is the success callback function on a successful page load. Note this will only work on sites within your domain to prevent XSS. Other domains will have to be handled server side
$.get(
yourURL,
function(data, textStatus, jqXHR) {
//load the iframe here...
}
);
There is no need to make a separate HTTP request to check beforehand.
You could switch the logic around: only display the iframe if it has been loaded successfully. For this purpose, you can attach an onload event listener to the iframe.
See this related question for details: Capture iframe load complete event

xmlhttp request has strange behavior and has status = 0

I have a Google Chrome extension that upon pressing a button executes an xmlhttp request to a server. I'm currently handling the error if the server is down. What I want to achieve is to retry the request after an increasing number of seconds. That's how I do it:
var execute = function(method, url, i){
//if timeout doesn't exist, create one
if(!i){
i = 1000;
}
var xmlhttp = new XMLHttpRequest();
xmlhttp.open(method, url, true);
xmlhttp.onreadystatechange = function(){
if (xmlhttp.status != 200) {
// Handle error, retry request
console.log("xmlhttp.status = " + xmlhttp.status + " and xmlhttp.readyState = " + xmlhttp.readyState);
setTimeout("execute('"+method+"', '"+url+"', "+i*2+")", i);
return;
}
};
xmlhttp.send(null);
}
Basically if there is some kind of problem I retry again the request. If the server is up, there is no problem at all, but if the server is down JavaScript throws me an error saying:
PUT http://localhost:3000/buy/2/id=1329664820124
executepopup.html:127
(anonymous function)
Which is not really meaningful, but however. The status in the log says "0", which is pretty lame too. If I turn on the server again while this is going on, it should stop doing this, but instead also if it succeeds (I see a log in the server that tells me that it received the request), it keeps calling the execute method. I don't know how to stop this recursion if the server turns on. Am I doing something wrong? Is this state equal zero the problem?
Thanks a lot
Solving the problem
onreadystatechange is triggered for every state change, from state 0 to 4, and many times between. You should only be interested in readyState 4, because the request has fully finished at that point.
To get your method to work, check whether xmlhttp.readyState == 4:
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
Fixing your horrible implementation of setTimeout
setTimeout("execute('"+method+"', '"+url+"', "+i*2+")", i); is not the right way to call a function again. Since you're developing in a Chrome extension, you can use the following format for setTimeout:
setTimeout(execute, i, method, url, i*2);
// Calls execute(method, url, i*2) after i milliseconds.

Categories