I want to check, if a website is reachable with XMLHttpRequest.
I wrote a JS-function: UrlExsists(url); to try and establish a connection.
function UrlExists(url) {
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
if (http.status != 404) {
console.log("did work:" + url)
} else {
console.log("did not work:" + url)
}
};
When i go to my browser console and call the function like so:UrlExsists("https://www.google.com/");, the following is displayed in the console:
"XHR HEAD https://www.google.com/ [HTTP/2.0 200 OK 668ms]"
But It fails due to "Cross-Origin Request Blocked" and a Network Error occurs. = >img as reference
If I call UrlExsists("https://www.google.com/test"); the following is displayed:
"XHR HEAD https://www.google.com/test [HTTP/2.0 404 Not Found 0ms]"
And again "Cross-Origin Request Blocked" and Network Error. = > img as reference
Now these Status codes 404 and 200 are exactly, what i want, but how do i get these in javascript, to determine if the given website is available?
And if I'm on the wrong track, can someone maybe nod me to the right one?
I think, I found a solution for my problem.
The fetch API seems to do just what I want.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
I did as the accepted answer from Kaiido instructed:
Check if online resource is reachable with JavaScript, not requiring the The Same Origin Policy to allow it
It is not possible due to the CORS error (you have no right to load other site's script, if it is not enable with Cross-Origin Resource Sharing: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). You just cant get the information, not even the HTTP response code.
The only workaround I see is append to the DOM a css request. And checking if the css successfully loaded. But its not a general solution, you need to pick some css class and check if it is loaded. And also you need to disable the cache with HTML meta tags.
You also can append css link tag dynamically (description: https://gist.github.com/chrisyip/1403858)
<link rel="stylesheet" type="text/css" href='https://mysite/custom.css'>
In the cusom css you need some unique class like:
.url-exists {
}
And after some delay (like 3-5 seconds timeout), you check if the css is successfully loaded:
function verifyStyle(selector) {
var rules;
var haveRule = false;
if (typeof document.styleSheets != "undefined") { //is this supported
var cssSheets = document.styleSheets;
outerloop:
for (var i = 0; i < cssSheets.length; i++) {
//using IE or FireFox/Standards Compliant
rules = (typeof cssSheets[i].cssRules != "undefined") ? cssSheets[i].cssRules : cssSheets[i].rules;
for (var j = 0; j < rules.length; j++) {
if (rules[j].selectorText == selector) {
haveRule = true;
break outerloop;
}
}//innerloop
}//outer loop
}//endif
return haveRule;
}//eof
var ok = verifyStyle(".url-exists");
If the variable ok is true then the given url (https://mysite/) is accessible.
I am relatively new to JSON. I have read the tutorial and trying to implement it but no luck.
Basically I have an external URL that gives JSON data/feed. The data is in the form of array. Now I am trying to write a JavaScript Program (on my local) that would get the data out of this URL and would put in my html.
Here is the function. It includes the external link also.
But I am not getting any result. Just empty.
Am I missing something or what I am doing wrong?
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Index Page</title>
</head>
<body>
<div id="id01"></div>
<script>
var xmlhttp = new XMLHttpRequest();
var url = "http://mpatrizio-001-site5.smarterasp.net/categoryList.php?D=B7ACEF70-4901-41C8-930F-D4D681D82DAA";
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var myArr = JSON.parse(xmlhttp.responseText);
myFunction(myArr);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
function myFunction(arr) {
var out = "";
var i;
for(i = 0; i < arr.length; i++) {
out += arr[i].CategoryID + '<br>';
}
document.getElementById("id01").innerHTML = out;
}
</script>
</body>
</html>
UPDATE:
After being pointed in the right direction by you guys (thank you very much for that), I have found that the request is being blocked by server due to some CORS error. I am studying it.
Please review the following image of the error I got in the console.
From it, can you specifically point out the solution?
Append --disable-web-security (at path C;...\chrome.exe) in chrome's exe properties preceded by a space.
More Elegant Solution:
Other solution will be on server side. Which is to create crossdomain.xml and clientaccesspolicy.xml file on server. It's structure is like:
crossdomain.xml:
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>
</cross-domain-policy>
clientaccesspolicy.xml:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
Some of the tutorials are:
http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000469.html
http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
Its specification is:
http://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf
Other tutorials:
https://msdn.microsoft.com/en-us/library/cc197955(v=vs.95).aspx
What you are trying to do, Is a cross domain request. A cross domain request is also called a JSONP request amongst many more others and has two restrictions:
The first is that it restricts you only to "GET" requests, meaning you cannot issue a "POST" request to the cross domain server.
The second is that you are very limited by the server, meaning that if the server won't allow, you cannot get any data.
I would suggest you to read more about cross domain request before trying to go through this.
You are probably trying to execute an XMLHttpRequest to a domain that is different than your page is on, the browser will block this request. To allow the request you have to use CORS.
You can open the developer tools in Chrome (F12) and check for any error messages related to
"No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '[domainname]' is therefore not allowed access."
Thank to Muhammad Imran, Barr J and Luuk Moret, I am finally able to solve my problem.
It was the Cross domain request that's why it was not allowing me to get data.
So what I did,
I checked using test-cors.org the server to which I was sending request to see if CORS is configured or not. And the server was configured.
Then I installed this plugin for chrome, "Allow-Control-Allow-Origin: *" This plugin allows to you request any site with ajax from any source. Adds to response 'Allow-Control-Allow-Origin: *' header and Whola!. That solved my problem.
I hope this would help someone else.
I'm merely trying to grab the html from one of my other sites on the server and print it on the current site. Here's basically what I'm doing:
// The object
var xmlhttp = new XMLHttpRequest();
// When a button is pressed, we get the html
function printJSON(action)
{
otherURL = "http://www.my.domain.com/other.php?action=" +action;
xmlhttp.open('GET',otherURL,true);
xmlhttp.send();
}
// and then print it in this div
xmlhttp.onreadystatechange = function
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
$('JSON_output').innerHTML = xmlhttp.responseText;
}
}
and the error I'm receiving is:
XMLHttpRequest cannot load http://www.my.domain.com/other.php?action=SEARCH. Origin http://my.domain.com is not allowed by Access-Control-Allow-Origin.
Which seems strange, because this is one site on the server trying to access another site right within the same folder. Is there something I need to adjust on my server? An attribute in xmlhttp I need to set?
Cheers!
http://www.my.domain.com and http://my.domain.com are two different domains (note the www) according to the JavaScript same-origin policy.
If www.my.domain.com and my.domain.com point to the same place, the simplest solution would be to make otherURL relative; start it with "/other.php?action="; that way, it will always be on the same domain as your page.
If they do not, point to the same place, there is a much more complicated solution involving your server outputting additional headers called Cross Origin Resource Sharing; here's an overview.
I created a html/javascript website running on an Apache Webserver on Mac OS X. This website consumes a .NET Webservice with JSON via XmlHttpRequest. This Webservice is running on a Windows Vista machine.
The website is accessible with this url: http://macintosh.companyname.local/~username/Sitename/index.html.
When I open the website on the Mac with Safari with this url I don't get any JSON data back from the Webservice.
When I open the website with the URL file://Users/username/Sites/Sitename/index.html it works perfectly.
My first thoughts are that is has something to do with XmlHttpRequest and it's security restrictions in many browsers, but I am not sure why it doesn't work when I call the site via the webserver instead of the absolute path to the html file.
Here the code I use to call the Webservice:
<div id="eigenRisico" class="panel" title="Eigen Risico">
<h2>Eigen Risico Per Polis</h2>
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://webserviceurl/GetEigenRisicoVerzekerde", true);
xhr.onreadystatechange = function(){
if (xhr.readyState === 4) {
var result = eval('(' +xhr.responseText+')');
var ihtml="";
var j = 0;
for(i = 0; i < result.d.length/2; i++) {
ihtml=ihtml+"<fieldset><div class='row'><label>Polisnummer:</label><span>"+result.d[j]+"</span></div>";
j++;
ihtml=ihtml+"<div class='row'><label>Resterend Eigen Risico:</label><span>&euro "+result.d[j]+"</span></div></fieldset>";
j++;
}
document.getElementById('eigenRisico').innerHTML = ihtml;
}
};
xhr.setRequestHeader("content-type", "application/json");
var postData = '{"bsn": "999999999"}';
xhr.send(postData);
</script>
</div>
Does somebody knows why this is happening?
You can't do cross-domain ajax requests
See http://en.wikipedia.org/wiki/Same_origin_policy
You can get around this by setting up a proxy page on your own domain that will take the request and redirect it, then redirect the output back to you.
Are you running PHP? or other server-side processing?
Edit
Just to clarify your original problem, when reading from file://, the security policy is different that from http://. the local resource is considered trusted, and as such the ajax request is allowed to go through. As a web address, it just looks like one website is doing things in your name that maybe it shouldn't.
I have to call domain A.com (which sets the cookies with http) from domain B.com.
All I do on domain B.com is (javascript):
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = "A.com/setCookie?cache=1231213123";
head.appendChild(script);
This sets the cookie on A.com on every browser I've tested, except Safari.
Amazingly this works in IE6, even without the P3P headers.
Is there any way to make this work in Safari?
From the Safari Developer FAQ:
Safari ships with a conservative cookie policy which limits cookie writes to only the pages chosen ("navigated to") by the user. This default conservative policy may confuse frame based sites that attempt to write cookies and fail.
I have found no way to get around this.
If it's worth anything, Chrome doesn't set the cookies either if you use the <script> appending method, but if you have a hidden <img> with the same source, Chrome works in addition to the rest of the browsers (except, again, Safari)
Here is a solution which works:
http://anantgarg.com/2010/02/18/cross-domain-cookies-in-safari/
This might not work for everyone, but I came across this issue because I was serving a React App from a different host than the API, and the solution that ultimately worked was to use DNS:
Our client was being served from www.company-name.com and our API was on company-name.herokuapp.com. By making a CNAME record api.company-name.com --> company-name.herokuapp.com, and having our client use that subdomain for API calls, Safari stopped considering it a "third-party" cookie.
The upside is that there's very little code involved, and it's all using well-established stuff... The downside is that you need some control/ownership over the API host if you're going to use https - they need a certificate that's valid for the client domain, or users will get a certificate warning - so this wouldn't work (at least not for something end-user-facing) if the API in question isn't yours or a partner's.
Working method 2014-2016:
You have to do window.open to the domain / assign a cookie / close the popup, the domain is now safelisted.
Original post # PHP multiple cookies not working on iPad / iPhone browser
There is a bit of an evil trick assuming they have flash installed.
I'm not sure if it still works or not, but Flash'es "Local Shared Objects" aka Flash Cookies could help you circumnavigate Safari's same-domain policies.
Local Shared Object Tutorial
However, it may be complicated to implement, to say the least.
Wiki Article on LSO's
Additonally, LSO's are comming into the light as being a security nightmare:
Electronic Privacy Information Centre on LSO's
Flash Cookies: The Silent Privacy Killer
So think carefully before using them.
A post to a hidden <iframe> can allow you to by-pass this restriction in Safari -- http://gist.github.com/586182:
<?php
header('P3P: CP=HONK');
setcookie('test_cookie', '1', 0, '/');
?>
<div id="test_cookie" style="position: absolute; top: -10000px"></div>
<script>
window.setTimeout(function() {
if (document.cookie.indexOf('test_cookie=1') < 0) {
var
name = 'test_cookie',
div = document.getElementById(name),
iframe = document.createElement('iframe'),
form = document.createElement('form');
iframe.name = name;
iframe.src = 'javascript:false';
div.appendChild(iframe);
form.action = location.toString();
form.method = 'POST';
form.target = name;
div.appendChild(form);
form.submit();
}
}, 10);
</script>
There is a proper workaround for this working in 2015. Let's say there is website y.com which includes iframe with site x.com. The x.com iframe wants to store a cookie. That is not permitted by Safari policy, however, y.com is able to store it. So y.com must listen to messages from x.com and then store the cookie itself.
var _cookieEvMth = window.addEventListener ? "addEventListener" : "attachEvent";
var _cookieEvAction = window[_cookieEvMth];
var _cookieEv = _cookieEvMth == "attachEvent" ? "onmessage" : "message";
_cookieEvAction(_cookieEv, function(evt){
if(evt.data.indexOf('cookieset')!=-1){
var datack = evt.data.split('|');
YOUR_CUSTOM_COOKIE_SAVE_METHOD(datack[1],datack[2],datack[3]);
}
},false);
When x.com needs to store the cookie, it must post a message to y.com:
window.parent.postMessage('cookieset|'+ckName+'|'+ckVal+'|'+days,'*');
Also you can work your way to post message to the iframe if you want to read the cookie. Or you can include it as parameter in x.com iframe url using javascript:
iframe.setAttribute('url','x.com/?cookieval='+YOUR_COOKIE_GET_METHOD('cookiename'));
A workaround we just came up with at my job was to set the cookie via a window.open() - it may not be optimal for you (as you'll have an ugly ass popup window open), but it worked well for us. We had to have a popup window open anyway for OAuth authentication.
So the jist of what we did was:
User clicks a link from B.com
Popup window opens to A.com/setCookie
A.com sets its cookie, and then redirects to B.com in the proper place
Again, not valid in all solutions, but it worked in ours. Hope this helps.
I know this question is rather old, but this helped me to solve cookies problem:
var cookieForm = document.createElement("form");
cookieForm.action = "A.com/setCookie?cache=1231213123";
cookieForm.method = "post";
document.body.appendChild(cookieForm);
cookieForm.submit();
The idea to make a form post on a page that sets your cookies.
*EDIT*
This workaround has been reported closed in WebKit.
Luca,
Ok, so this answer is two years old, but... you can set a cookie from an iframe if you post a form to a hidden iframe. You can do this by creating a form:
<form id="myiframe" action="http://yourdomain.com" method="POST" target="iframe_target">
Then in Javascript, get a reference to the form and call submit:
document.getElementsByTagName('form')[0].submit();
You can listen to the iframe's onload, or you can have your iframe action page issue some javascript that signals the load. I have tested this in Safari and Chrome, and it works.
Cheers.
Perhaps pragmatically create and click a link with an href="A.com/setCookie?cache=1231213123" and a target attribute pointing to a hidden iframe. That may bypass Safari's policy of user navigation for setting cookies (I don't have Safari handy to test.)
I did some extensive investigation around this when I was trying to deploy a site that used Windows Live ID, which depended on the ability to be able to set 3rd party cookies in order to log out. It just... didn't work. Nothing we could do would get it to work. The Live ID team also did extensive investigation and their answer was "can't make it work".
Note this line:
script.src = "A.com/setCookie?cache=1231213123";
I could not get this working until I added the http, i.e.
script.src = "http://A.com/setCookie?cache=1231213123";
I found a simple solution. You just need for first time setting cookie to check if request come from the same origin or not, if not as usual you need to return into iframe a script that will repeat this request, already having permission to assign cookie. After that you can do other request directly through iframe accessing this cookie. This helped me in my tracking system. Try, this works well.
Its worth noting that this restriction in Safari doesn't apply across subdomains. So if you directly visit sitea.com, then you can set cookies from subdomain.sitea.com without direct user interaction (iframe/JavaScript).
This was relevant for my case when developing an API. If you're visitors are arriving at mysite.com, and then you want some JavaScript to interact with your API, then if the API is hosted at api.mysite.com, then it will work on Safari.
Place this JavaScript on the page making cross-domain requests, http://example1.com/index.html:
<script>
var gup = function(name, url) {
if(!url) url = location.href;
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( url );
return results == null ? null : results[1];
}
var isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && navigator.userAgent && !navigator.userAgent.match('CriOS');
var n = gup("activated");
if(isSafari && n == null) {
//browser is Safari and cookies have not yet been activated
var current_url = location.protocol + '//' + location.host + location.pathname;
var query_string = '?callback=' + encodeURIComponent(current_url + '?activated=1');
var new_url = 'http://example2.com/activate.php' + query_string;
window.location.href = new_url;
}
//the rest of your code goes here, and you can now set cross-domain cookies on Safari
</script>
Then create a file on the other server, which needs to set cookies, http://example2.com/activate.php:
<?php
if(isset($_GET['callback'])) {
header('Location: '.$_GET['callback']);
exit();
} else {
//in case callback param is not set, simply go back to previous page
echo "<script>";
echo "window.history.back();";
echo "</script>";
exit();
}
?>
Here's how this works:
When http://example1.com/index.html is first visited, a check is made to see whether the browser is Safari and whether a GET parameter of the name "activated" does not exist. If both conditions are met (which will happen on the first visit for a Safari browser), then the browser is redirected to http://example2.com/activate.php with a GET parameter, "callback", containing the calling URL appended with an "activated" parameter.
http://example2.com/activate.php simply redirects back to the URL contained in the GET parameter, "callback".
When http://example1.index.html is now hit this second time after being redirected-to, the GET parameter, "activated" will now be set, so the conditional from step 1 will not execute, thus allowing the script to continue execution.
This fulfills Safari's requirement of having the browser visit the 3rd party domain at least once in order to start setting cookies.
Try something like:
var w = window.open("A.com/setCookie?cache=1231213123");
w.close();
It may bypass safari's security policy.
It isn't the missing type-attribute thats annoying you ?-)
<script type="text/javascript">
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.src = "A.com/setCookie?cache=1231213123";
head.appendChild(script);
</script>