I want to make a web page request only if that web page is available. I have written my app using angularjs + javascript. Is there any way to determine whether a webpage is available or not using javascript ?
If the page in question is on a different origin, you can't without using a server somewhere or relying on the other page implementing Cross-Origin Resource Sharing and supporting your origin, because of the Same Origin Policy.
If the page in question is on the same origin, you can do an ajax call to query it:
var xhr = new XMLHttpRequest();
xhr.open("HEAD", url);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// It worked
} else {
// It didn't
}
}
};
xhr.send();
You can make an AJAX request with XMLHttpRequest, but instead of POST or GET, you should use the HEAD HTTP verb.
Related
I'm doing the JavaScript challenges at FreeCodeCamp. One of them is to create a web page that retrieves and displays weather information.
First, I tried to use several providers (e. g. OpenWeatherMap, WeatherUnderground), which use the HTTP protocol to return weather data. It didn't work because of the mixed content error.
Next, I switched to a provider, which delivers the data via HTTPS. I got rid of the mixed content problem, but got another one:
XMLHttpRequest cannot load https://api.weatherbit.io/v1.0/current?lat=55.7767723&lon=37.6090795&units=S&key=XXXXXXXX. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://s.codepen.io' is therefore not allowed access. The response had HTTP status code 403.
I tried to implement CORS according to this tutorial:
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
}
[...]
var url = "https://api.weatherbit.io/v1.0/current?lat=" + position.coords.latitude + "&lon=" + position.coords.longitude + "&units=S&key=XXXXXXXX";
var xhr = createCORSRequest('GET', url);
if (xhr) {
xhr.onload = function() {
var responseText = xhr.responseText;
console.log("Response: " + responseText);
};
xhr.onerror = function() {
console.log('There was an error!');
};
xhr.send();
}
When I call xhr.send() I still get the error.
How can I fix it?
Note: I'm looking for a solution that will run in CodePen.
Update 1 (23.03.2017 11:35 MSK): I tried to implement sideshowbarker's answer and modified the code like this:
function getCurrent(json){
console.log("getCurrent called");
console.log(json.data.temp);
console.log(json.data.precip);
}
function updateWeather() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var url = "https://api.weatherbit.io/v1.0/current?callback=getCurrent&lat=" + position.coords.latitude + "&lon=" + position.coords.longitude + "&units=S&key=XXXXXXXXX";
console.log("url: " + url);
$.get(url, function(val){});
});
} else {
console.log("Cannot obtain location data");
};
}
updateWeather();
The result:
Update 2 (23.03.2017 13:29 MSK): This one works.
function getCurrent(json) {
console.log("getCurrent called");
console.log(JSON.stringify(json));
// TODO: Update the UI here
}
function updateWeather() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var url = "https://api.darksky.net/forecast/XXXXXXXXX/37.8267,-122.4233?callback=getCurrent";
var script = document.createElement('script');
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
});
}
}
updateWeather();
The Weatherbit.io API doesn’t support cross-origin requests made from XHR.
Instead the API requires you make the requests using a script element with a JSONP callback:
<script>
function getCurrent(json){
console.log(json.data.temp)
console.log(json.data.precip)
}
</script>
<script
src="https://api.weatherbit.io/v1.0/current?callback=getCurrent&lat=NNN&lon=NNN&units=S&key=XX"></script>
Of course you likely want to have your code inject that script element with the URL and params.
That’s method of injecting the script element with a JSONP callback is the only direct method they support for using their API from a web app.
There’s no way your code will work if it instead makes the request to their API using XHR; they don’t send the necessary Access-Control-Allow-Origin response header, and so because that’s missing, your browser won’t let your client-side JavaScript access the response cross-origin.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explains why.
The only way you could use XHR to work with their API is if you set up a CORS proxy using code from https://github.com/Rob--W/cors-anywhere/ or something similar—or if you send your request through an public CORS proxy like https://github.com/Rob--W/cors-anywhere/ (which you don’t want to do because that’d give the owner of that service access to your Weatherbit.io API key).
The way the proxy works is that instead of using weatherbit.io URL, you use a proxy URL like https://cors-anywhere.herokuapp.com/https://api.weatherbit.io/v1.0/current…, and the proxy sends it on to weatherbit.io, gets the response back, then adds the Access-Control-Allow-Origin response header to the response it hands back to your code and that the browser sees.
I was in the process of completing the Weather App in FCC and came across the same issue. I was able to get it to work with the following line:
$.getJSON("https://api.weatherbit.io/v1.0/current?lat=##&lon=##&key=##", function(data){};
For whatever reason, it wouldn't work with just "http://", I had to change it to "https://" in order for it to work.
Not sure if that helps anyone in the future.
This is my first Ajax program and I can't fix the code because I'm not sure where/what the problem is.
The error(which I'm unable to interpret) while using the debugger is,
XMLHttpRequest cannot load http://localhost/function.txt. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
function calling()
{
var x;
if (window.XMLHttpRequest) {
x = new XMLHttpRequest();
} else {
x = new ActiveXObject("Microsoft.XMLHTTP");
}
x.onreadystatechange = function(){
if(this.readyState == 4 && this.status == 200)
{
document.getElementById("block").innerHTML = this.responseText;
}
};
x.open("GET", "http://localhost/function.txt",true);
x.send();
}
function.txt
<html>
<head></head>
<body>
<h2>Ajax is working</h2>
</body>
</html>
Is your js located at the same location as your function.txt?
For more information about CORS, have a look at this link: https://www.html5rocks.com/en/tutorials/cors/
UPDATE:
This works for me, I think there is maybe something with your Apache settings...
function calling()
{
var xhr = new XMLHttpRequest(),
method = "GET",
url = "function.txt";
xhr.open(method, url, true);
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
alert(xhr.responseText);
}
};
xhr.send();
}
calling();
You cannot make Ajax calls to a url from a different domain if said domain does not explicitly allow it (via 'Access-Control-Allow-Origin' header).
Your error means that you're making your Ajax call from another domain. If your function.txt file is located at the same location as your js, try using relative path in your .open().
You are attempting a CORS request, which is unsafe and is prohibited by browsers by default. If you are in control of the target site, you can enable CORS. If that's not the case, then you will need to write a page which will be used as a proxy, that is, you will send the request to this page instead of the target site's page. The page, on its turn will send the request to the target page and send the output to the browser. While this is a workable solution you will need to make sure that all the absolute paths of the target site are handled well.
How can to request url or website address and show response code with javascript or jquery?
i.e
request www.google.com
if (response_code = 200) {
print "website alive"
} else if (response_code = 204) {
print "not found";
}
I'm assuming from the jquery tag that you mean to do this in a browser, not from a server running NodeJS or similar (although there is a NodeJS module for jQuery).
Although you can request URLs and see the response code using the XMLHttpRequest object, the Same Origin Policy will prevent your accessing virtually any sites other than the one the page itself was loaded from. But if you're pinging the server your page was loaded from to make sure it's still there, you can do that:
function ping(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange;
xhr.open("get", url);
xhr.send();
function handleStateChange() {
if (xhr.readyState === 4) { // Request is complete
callback(xhr.status); // Tell the callback what the status code is
}
}
}
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
Is it possible to prevent the browser from following redirects when sending XMLHttpRequest-s (i.e. to get the redirect status code back and handle it myself)?
Not according to the W3C standard for the XMLHttpRequest object (emphasis added):
If the response is an HTTP redirect:
If the origin of the URL conveyed by the Location header is same origin
with the XMLHttpRequest origin and the
redirect does not violate infinite
loop precautions, transparently
follow the redirect while observing
the same-origin request event rules.
They were considering it for a future release:
This specification does not include
the following features which are being
considered for a future version of
this specification:
Property to disable following redirects;
but the latest specification no longer mentions this.
The new Fetch API supports different modes of redirect handling: follow, error, and manual, but I can't find a way to view the new URL or the status code when the redirection has been canceled. You just can stop the redirection itself, and then it looks like an error (empty response). If that's all you need, you are good to go. Also you should be aware that the requests made via this API are not cancelable yet. They are now.
As for XMLHttpRequest, you can HEAD the server and inspect whether the URL has changed:
var http = new XMLHttpRequest();
http.open('HEAD', '/the/url');
http.onreadystatechange = function() {
if (this.readyState === this.DONE) {
console.log(this.responseURL);
}
};
http.send();
You won't get the status code, but will find the new URL without downloading the whole page from it.
No you there isn't any place in the API exposed by XMLHttpRequest that allows you to override its default behaviour of following a 301 or 302 automatically.
If the client is running IE on windows then you can use WinHTTP instead to set an option to prevent that behaviour but thats a very limiting solution.
You can use responseURL property to get the redirect destination or check whether the response was ultimately fetched from a location you accept.
This of course means the result is fetched anyway, but at least you can get the necessary info about the redirect destination and for example detect conditions when you would like to discard the response.
I extended user's answer to include an abort() call. It seems like this prevents the server from sending too much data when all you want is the redirect url.
var url = 'the url'
var http = new XMLHttpRequest();
http.open('GET', url);
http.onreadystatechange = function() {
if (this.readyState === this.DONE) {
console.log(this.responseURL)
this.abort() // This seems to stop the response
}
}
http.send()
In real life I wrapped the above code in a promise, but it made the code hard to read.
Also, I don't understand why getting the redirect url needs to be this difficult, but that is a question for another time and place.
It is not possible to handle redirect or 302 status at client side as answered in other comments. However you can prevent redirection. To do that you can set request header "X-Requested-With" with "XMLHttpRequest"
xhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");
This should be done after open but before send. Example below
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
reqObj.success(JSON.parse(this.responseText))
} else if (this.status != 200) {
reqObj.error(this.statusText)
}
};
xhttp.open(reqObj.type, reqObj.url, reqObj.async);
xhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhttp.send();