Javascript CORS JSON/JSONP Request - javascript

I have browsed most CORS and JSON request topics, and cannot understand why this first script works, but not the second. I would love to be educated in the ways of CORS and Javascript and XMLHTTPRequest2 and AJAX.
This works:
function wfs() {
var url = 'http://routes.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/api/0.3/51.22545,4.40730,%5B51.22,4.41,51.2,4.41%5D,51.23,4.42/car.js?lang=de&units=miles&callback=getRoute';
var script = document.createElement('script');
script.type="text/javascript";
script.src=url;
document.getElementsByTagName('head')[0].appendChild(script);
}
function getRoute(response) {
console.log(response);
}
This does not work:
function wfs() {
var url = 'http://routes.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/api/0.3/51.22545,4.40730,%5B51.22,4.41,51.2,4.41%5D,51.23,4.42/car.js?lang=de&units=miles';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function(e) {
if (this.status == 200) {
var json = this.response;
console.log(json);
}
};
xhr.send();
}
Firebug shows a Red 200 Null Response.
However, the second script does work when I use a different url:
var url = 'http://ip.jsontest.com/?mime=2';

The first domain, http://routes.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/api/0.3/51.22545,4.40730,%5B51.22,4.41,51.2,4.41%5D,51.23,4.42/car.js?lang=de&units=miles, does not implement CORS (i.e. does not send a usable Access-Control-Allow-Origin header). http://ip.jsontest.com/?mime=2 does. There is nothing you can do about this -- it depends on the server.
The first block of code uses JSONP. What this actually does is inject a script tag into the document. Script tags can have external sources (if they are not of the same scheme, they may be blocked for security reasons). This allows the server to essentially send you javascript code that you insert into a <script> that gets run immediately.

Related

No Access-Control-Allow-Origin using OneSignal setup

I am using OneSignal for web push messaging for a client website. I've followed the HTTPS setup. I went over it few times ensuring that everything was done right.
all the files were uploaded to the root of the domain
I've setup the manifest and put the needed initialize code in the header of the page
When I load the page I get:
Fetch API cannot load https://onesignal.com/api/v1players.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'https://example.com' is therefore not allowed access.
The response had HTTP status code 404. If an opaque response serves your needs,
set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I contacted the team directly, but they just copy pasted part of the documentation. No further assistance was given.
Using Chrome version 58 / Windows 10
What am I doing wrong?
https://onesignal.com/api/v1players responses apparently don’t include the Access-Control-Allow-Origin response header, and because they do not, your browser blocks your frontend JavaScript code from accessing the responses.
There are no changes you can make to your own frontend JavaScript code nor backend config settings that’ll allow your frontend JavaScript code to make requests the way you’re trying directly to https://onesignal.com/api/v1players and get responses back successfully.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explains in more detail but the gist of it is that for CORS, the server the request is being sent to must be configured to send the Access-Control-Allow-Origin response header.
Anyway https://documentation.onesignal.com/docs/web-push-sdk-setup-https has official docs that explain their supported SDK, which apparently requires you to do something more like this:
<head>
<link rel="manifest" href="/manifest.json">
<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async></script>
<script>
var OneSignal = window.OneSignal || [];
OneSignal.push(["init", {
appId: "YOUR_APP_ID",
autoRegister: false,
notifyButton: {
enable: true /* Set to false to hide */
}
}]);
</script>
</head>
The accepted answer is ok, you can solve most of the requirements by using tags:
OneSignal.push(function() {
/* These examples are all valid */
OneSignal.sendTag("key", "value");
OneSignal.sendTag("key", "value", function(tagsSent) {
// Callback called when tags have finished sending
});
OneSignal.sendTag("key", "value").then(function(tagsSent) {
// Callback called when tags have finished sending
});
});
But in case you want to edit the device information, there is no way (as of today) to edit the device metadata with the WebPush SDK. I needed to update the location periodically, and I didn't want to use tags. So, I sent the PUT request to https://onesignal.com/api/v1players like this:
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") { //ie8 ie9
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
};
//then every time I needed to update the device
var url = 'https://onesignal.com/api/v1/players/' + playerId;
var xhr = createCORSRequest('PUT', url);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onload = function() {}; //success
xhr.onerror = function() {}; //error
var deviceInfo = {
"app_id": oneSignalAppId,
"timezone": (currentDateTime.getTimezoneOffset()) * -60, //offset from utc
//whatever fields you need to update
};
xhr.send(JSON.stringify(deviceInfo));

Why does this email sending function not work?

Heres my email sending function:
function send() {
var key = "dJdJekCVAFIqvUJ13DEczZjgIh_4MyeIGEHz2GBYKFe";
var message_name = "defender_send_message";
var data = {};
data.value1 = document.getElementById('textBox').value;
data.value2 = localStorage.getItem("AdminsEmail");
var url = "https://maker.ifttt.com/trigger/" + message_name + "/with/key/" + key;
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
console.log("Message Sent");
}
}
}
xmlhttp.open('POST', url, true);
xmlhttp.responseType = 'json';
xmlhttp.send(new FormData(data));
}
I wanted to create an email sending function with only pure js, not jquery or anything. I get the following errors when i click send:
(ignore the first error i fixed that already)
I had a jquery function that worked (but i had to get rid of it):
var message = localStorage.getItem("Message");
console.log(message + localStorage.getItem("AdminsEmail"));
var key = "dJdJekCVAFIqvUJ13DEczZjgIh_4MyeIGEHz2GBYKFe"; // << YOUR KEY HERE
var message_name = "defender_send_message"; // << YOUR MESSAGE NAME HERE
var url = "https://maker.ifttt.com/trigger/" + message_name + "/with/key/" + key;
$.ajax({
url: url,
data: {value1: message,
value2: localStorage.getItem("AdminsEmail")},
dataType: "jsonp",
complete: function(jqXHR, textStatus) {
console.log("Message Sent");
}
});
why would this work and my other function not?
EDIT 2 : Since it seems the endpoint doesn't actually return JSON, I think your original jQuery code wasn't correct either. You need to do more research into this iftt.com platform and how to use it. From what I can tell, it's meant to be used in a mobile app, not in the browser- it would be a normal POST XHR then, and CORS doesn't apply to mobile apps. They have this page for testing the endpoint- notice that it gives you an example using curl, a command-line tool, where again CORS doesn't apply. So I think you need to rethink things, this service is not designed to be used from a browser, like you are trying to do.
EDIT: since it turns out you are actually trying to use JSONP and not a plain XHR, all you need to do is implement that without jQuery- create a script tag with the server's URL and add a URL parameter to define your callback function to handle the data. This answer should give you the solution.
In your case the code might look like this :
http://www.codeply.com/go/bp/VRCwId81Vr
function foo(data)
{
// do stuff with JSON
console.log(data)
}
var script = document.createElement('script');
script.src = "https://maker.ifttt.com/trigger/defender_send_message/with/key/"+
"dJdJekCVAFIqvUJ13DEczZjgIh_4MyeIGEHz2GBYKFe?callback=foo";
document.getElementsByTagName('head')[0].appendChild(script);
Note that this doesn't work for me(but with your code, you would get Message sent printed to the console, so maybe you thought it was working?)- the response isn't JSON. Most likely the endpoint isn't actually meant to be used for JSONP?
My answer below only applies if you are trying to do a regular XHR in a browser without JSONP.
This happens because of the Cross Origin Resource Sharing policy of your browser. Your code is hosted at localhost, and it is trying to access a resource hosted at maker.ifttt.com through an XmlHttpRequest. In order to allow this to happen, the server at maker.ifttt.com would need to be configured to allow access from the localhost origin. Presumably you can not make that change as you don't control that server.
In your case, the best solution would be to make the request to maker.ifttt.com through your own server- CORS doesn't apply for server-to-server requests. Send the XmlHttpRequest to your server, take the data regarding the email from the request URL parameters, and then make the request to maker.ifttt.com using that data.

XMLHttpRequest, send and security restrictions

I thought I could catch an error in send like this
try {
xhr.send();
} catch(e) {
// fix-me: With the
// bookmarklet on a https page
// you can't even send a HEAD
// request due to security
// restrictions. Check for
// this case here.
console.log("xhr.send, e=", e, method, window.location.href, url)
debugger;
}
console.log("I am here now");
However I never get to that console.log statement in the catch block after xhr.send.
In the console I instead get a message like this.
Mixed Content: The page at 'about:blank' was loaded over HTTPS,
but requested an insecure XMLHttpRequest endpoint 'http://m.org/'.
This request has been blocked; the content must be served over HTTPS.
I am here now.
Is it supposed to work this way? (I am using Google Chrome.)
Is there any way to find out that there was an error? (Except looking in the console. ;-) )
UPDATE
#giuscri added the very good question if I did consider that this is async. I actually missed that it could be, but it is not. A bit surprisingly. ;-)
Please see the this example. It contains this code:
var url = "http://nowhere.org/";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
console.log("onreadystatechance, readyState=", xhr.readyState);
};
xhr.onprogress = function(event) {
console.log("onprogress, readyState=", xhr.readyState);
console.log("onprogress, event=", event);
};
xhr.onerror = function(event) {
console.log("onerror, readyState=", xhr.readyState);
console.log("onerror, event=", event);
};
var method = "HEAD";
xhr.open(method, url, true);
try {
xhr.send();
} catch(e) {
console.log("xhr.send, e=", e, method, window.location.href, url);
}
console.log("After send");
When you run this page from https:// (as in the link above) the onerror function is not run. If you run the same example from file:// then onerror is run.
Connecting from HTTPS to HTTP URIs drops the security given by the underlying encryption. Web browsers blocks such requests until explicitly allowed by the user in order to prevent data leakage over plaintext connections. Further, there is also a change in origin (scheme, domain, port).
I allowed Mixed Content for the page you linked and I got the error about the different origin in console. Looks like the code works.
By the way, support for synchronous requests using XMLHttpRequest is deprecated, because it blocks user interaction until the request completes.

XMLHttpRequest receiving no data or just "undefined"

i try to make a Firefox Addon which runs a XMLHttp Request in Javascript. I want to get the data from this request and send it to *.body.innerhtml.
That's my code so far...
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://xx.xxxxx.com", true);
xhr.send();
setTimeout(function() { set_body(xhr.responseHtml); }, 6000);
Instead of receiving the data, I get "undefined". If I change xhr.responseHtml to responseText I get nothing. I don't know why I'm getting nothing. I'm working on Ubuntu 12.04 LTS with Firefox 12.0.
If you need any more details on the script please ask!
Update:
set_body Function
document.body.innerHTML = '';
document.body.innerHTML = body;
document.close();
Update SOLVED:
I had to determine the RequestHeaders (right after xhr.open):
xhr.setRequestHeader("Host", "xxx");
For following Items: Host, Origin and Referer. So it seems there was really a problem with the same origin policy.
But now it works! Thanks to all!
when you set the last param of open to true you are asking for an async event. So you need to add a callback to xhr like so:
xhr.onReadyStateChange = function(){
// define what you want to happen when server returns
}
that is invoked when the server responds. To test this without async set the third param to false. Then send() will block and wait there until the response comes back. Setting an arbitrary timeout of 6 seconds is not the right way to handle this.
This code should work:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
set_body(xhr.responseText);
}
};
xhr.open("GET", "http://xx.xxxxx.com", true);
xhr.send();
Make sure that you are getting a correct response from URL http://xx.xxxxx.com. You may have a problem with cross-domain calls. If you have a page at domain http://first.com and you try to do XMLHttpRequest from domain http://second.com, Firefox will fail silently (there will be no error message, no response, nothing). This is a security measure to prevent XSS (Cross-site scripting).
Anyway, if you do XMLHttpRequest from a chrome:// protocol, it is considered secure and it will work. So make sure you use this code and make the requests from your addon, not from your localhost or something like that.

JavaScript/jQuery check broken links

I developed a small Javascript/jQuery program to access a collection of pdf files for internal use. And I wanted to have the information div of a pdf file highlighted if the file actually exist.
Is there a way to programmatically determine if a link to a file is broken? If so, How?
Any guide or suggestion is appropriated.
If the files are on the same domain, then you can use AJAX to test for their existence as Alex Sexton said; however, you should not use the GET method, just HEAD and then check the HTTP status for the expect value (200, or just less than 400).
Here's a simple method provided from a related question:
function urlExists(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
callback(xhr.status < 400);
}
};
xhr.open('HEAD', url);
xhr.send();
}
urlExists(someUrl, function(exists) {
console.log('"%s" exists?', someUrl, exists);
});
Issue is that JavaScript has the same origin policy so you can not grab content from another domain. This won't change by upvoting it (wondering about the 17 votes).
I think you need it for external links, so it is impossible just with .js ...
If the files are not on an external website, you could try making an ajax request for each file. If it comes back as a failure, then you know it doesn't exist, otherwise, if it completes and/or takes longer than a given threshold to return, you can guess that it exists. It's not always perfect, but generally 'filenotfound' requests are quick.
var threshold = 500,
successFunc = function(){ console.log('It exists!'); };
var myXHR = $.ajax({
url: $('#checkme').attr('href'),
type: 'text',
method: 'get',
error: function() {
console.log('file does not exist');
},
success: successFunc
});
setTimeout(function(){
myXHR.abort();
successFunc();
}, threshold);
You can $.ajax to it. If file does not exist you will get 404 error and then you can do whatever you need (UI-wise) in the error callback. It's up to you how to trigger the request (timer?) Of course if you also have ability to do some server-side coding you can do a single AJAX request - scan the directory and then return results as say JSON.
Like Sebastian says it is not possible due to the same origin policy. If the site can be published (temporarily) on a public domain you could use one of the link checker services out there. I am behind checkerr.org
As others have mentioned, because of JavaScript's same origin policy, simply using the function from the accepted answer does not work. A workaround to this is to use a proxy server. You don't have to use your own proxy for this, you can use this service for example: https://cors-escape.herokuapp.com (code here).
The code looks like this:
var proxyUrl = "https://cors-anywhere.herokuapp.com/";
function urlExists(url, callback) {
var sameOriginURL = proxyUrl + url;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
callback(xhr.status < 400);
}
};
xhr.open('HEAD', sameOriginURL);
xhr.send();
}
urlExists(someUrl, function(exists) {
console.log('"%s" exists?', someUrl, exists);
});

Categories

Resources