Noobie here. I'm writing a client script that needs to read an XML file from another domain. I tried using JSONP. I get a 200 response but the client can't access the returned data for some reason. I get two errors:
Resource interpreted as Script but transferred with MIME type text/xml
and
Uncaught SyntaxError: Unexpected token <
Here's the code (I've removed the XML url since it's confidential):
$(document).ready(function() {
$.getJSON("urlOfFilecallback=?", function(data) {
console.log(data)
})
});
When I try to render the data in the console I get:
ReferenceError: data is not defined
How can I fix this? Do I need to use a proxy?
You don't have to write your own proxy. You can use YQL if you want to here is an example how:
//sample site that returns xml
site = 'http://goo.gl/9iQWyG';
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from xml where url="' + site + '"') + '&format=xml&callback=?';
// Request that YSQL string, and run a callback function.
// Pass a defined function to prevent cache-busting.
$.getJSON(yql, function(data){
console.log(data.results[0]);
});
here is the jsfiddle check console.log.
(Usage limits of the public YQL API is 2,000 requests/hour per IP)
XML is not allowed for cross-domain requests by default.
However, with a little server-side programming you can create a proxy and load the data within your own domain, and output it as XML.
for more information see this Question
If you have access to the other domain side, you could also use this approach Cross Domain Request
Related
I'm trying to load a cross-domain HTML page using AJAX but unless the dataType is "jsonp" I can't get a response. However using jsonp the browser is expecting a script mime type but is receiving "text/html".
My code for the request is:
$.ajax({
type: "GET",
url: "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P#ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute",
dataType: "jsonp",
}).success( function( data ) {
$( 'div.ajax-field' ).html( data );
});
Is there any way of avoiding using jsonp for the request? I've already tried using the crossDomain parameter but it didn't work.
If not is there any way of receiving the html content in jsonp? Currently the console is saying "unexpected <" in the jsonp reply.
jQuery Ajax Notes
Due to browser security restrictions, most Ajax requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, port, or protocol.
Script and JSONP requests are not subject to the same origin policy restrictions.
There are some ways to overcome the cross-domain barrier:
CORS Proxy Alternatives
Ways to circumvent the same-origin policy
Breaking The Cross Domain Barrier
There are some plugins that help with cross-domain requests:
Cross Domain AJAX Request with YQL and jQuery
Cross-domain requests with jQuery.ajax
Heads up!
The best way to overcome this problem, is by creating your own proxy in the back-end, so that your proxy will point to the services in other domains, because in the back-end not exists the same origin policy restriction. But if you can't do that in back-end, then pay attention to the following tips.
**Warning!**
Using third-party proxies is not a secure practice, because they can keep track of your data, so it can be used with public information, but never with private data.
The code examples shown below use jQuery.get() and jQuery.getJSON(), both are shorthand methods of jQuery.ajax()
CORS Anywhere
2021 Update
Public demo server (cors-anywhere.herokuapp.com) will be very limited by January 2021, 31st
The demo server of CORS Anywhere (cors-anywhere.herokuapp.com) is meant to be a demo of this project. But abuse has become so common that the platform where the demo is hosted (Heroku) has asked me to shut down the server, despite efforts to counter the abuse. Downtime becomes increasingly frequent due to abuse and its popularity.
To counter this, I will make the following changes:
The rate limit will decrease from 200 per hour to 50 per hour.
By January 31st, 2021, cors-anywhere.herokuapp.com will stop serving as an open proxy.
From February 1st. 2021, cors-anywhere.herokuapp.com will only serve requests after the visitor has completed a challenge: The user (developer) must visit a page at cors-anywhere.herokuapp.com to temporarily unlock the demo for their browser. This allows developers to try out the functionality, to help with deciding on self-hosting or looking for alternatives.
CORS Anywhere is a node.js proxy which adds CORS headers to the proxied request.
To use the API, just prefix the URL with the API URL. (Supports https: see github repository)
If you want to automatically enable cross-domain requests when needed, use the following snippet:
$.ajaxPrefilter( function (options) {
if (options.crossDomain && jQuery.support.cors) {
var http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
options.url = http + '//cors-anywhere.herokuapp.com/' + options.url;
//options.url = "http://cors.corsproxy.io/url=" + options.url;
}
});
$.get(
'http://en.wikipedia.org/wiki/Cross-origin_resource_sharing',
function (response) {
console.log("> ", response);
$("#viewer").html(response);
});
Whatever Origin
Whatever Origin is a cross domain jsonp access. This is an open source alternative to anyorigin.com.
To fetch the data from google.com, you can use this snippet:
// It is good specify the charset you expect.
// You can use the charset you want instead of utf-8.
// See details for scriptCharset and contentType options:
// http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings
$.ajaxSetup({
scriptCharset: "utf-8", //or "ISO-8859-1"
contentType: "application/json; charset=utf-8"
});
$.getJSON('http://whateverorigin.org/get?url=' +
encodeURIComponent('http://google.com') + '&callback=?',
function (data) {
console.log("> ", data);
//If the expected response is text/plain
$("#viewer").html(data.contents);
//If the expected response is JSON
//var response = $.parseJSON(data.contents);
});
CORS Proxy
CORS Proxy is a simple node.js proxy to enable CORS request for any website.
It allows javascript code on your site to access resources on other domains that would normally be blocked due to the same-origin policy.
CORS-Proxy gr2m (archived)
CORS-Proxy rmadhuram
How does it work?
CORS Proxy takes advantage of Cross-Origin Resource Sharing, which is a feature that was added along with HTML 5. Servers can specify that they want browsers to allow other websites to request resources they host. CORS Proxy is simply an HTTP Proxy that adds a header to responses saying "anyone can request this".
This is another way to achieve the goal (see www.corsproxy.com). All you have to do is strip http:// and www. from the URL being proxied, and prepend the URL with www.corsproxy.com/
$.get(
'http://www.corsproxy.com/' +
'en.wikipedia.org/wiki/Cross-origin_resource_sharing',
function (response) {
console.log("> ", response);
$("#viewer").html(response);
});
The http://www.corsproxy.com/ domain now appears to be an unsafe/suspicious site. NOT RECOMMENDED TO USE.
CORS proxy browser
Recently I found this one, it involves various security oriented Cross Origin Remote Sharing utilities. But it is a black-box with Flash as backend.
You can see it in action here: CORS proxy browser
Get the source code on GitHub: koto/cors-proxy-browser
You can use Ajax-cross-origin a jQuery plugin.
With this plugin you use jQuery.ajax() cross domain. It uses Google services to achieve this:
The AJAX Cross Origin plugin use Google Apps Script as a proxy jSON
getter where jSONP is not implemented. When you set the crossOrigin
option to true, the plugin replace the original url with the Google
Apps Script address and send it as encoded url parameter. The Google
Apps Script use Google Servers resources to get the remote data, and
return it back to the client as JSONP.
It is very simple to use:
$.ajax({
crossOrigin: true,
url: url,
success: function(data) {
console.log(data);
}
});
You can read more here:
http://www.ajax-cross-origin.com/
If the external site doesn't support JSONP or CORS, your only option is to use a proxy.
Build a script on your server that requests that content, then use jQuery ajax to hit the script on your server.
Just put this in the header of your PHP Page and it ill work without API:
header('Access-Control-Allow-Origin: *'); //allow everybody
or
header('Access-Control-Allow-Origin: http://codesheet.org'); //allow just one domain
or
$http_origin = $_SERVER['HTTP_ORIGIN']; //allow multiple domains
$allowed_domains = array(
'http://codesheet.org',
'http://stackoverflow.com'
);
if (in_array($http_origin, $allowed_domains))
{
header("Access-Control-Allow-Origin: $http_origin");
}
I'm posting this in case someone faces the same problem I am facing right now. I've got a Zebra thermal printer, equipped with the ZebraNet print server, which offers a HTML-based user interface for editing multiple settings, seeing the printer's current status, etc. I need to get the status of the printer, which is displayed in one of those html pages, offered by the ZebraNet server and, for example, alert() a message to the user in the browser. This means that I have to get that html page in Javascript first. Although the printer is within the LAN of the user's PC, that Same Origin Policy is still staying firmly in my way. I tried JSONP, but the server returns html and I haven't found a way to modify its functionality (if I could, I would have already set the magic header Access-control-allow-origin: *). So I decided to write a small console app in C#. It has to be run as Admin to work properly, otherwise it trolls :D an exception. Here is some code:
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
//foreach (string s in prefixes)
//{
// listener.Prefixes.Add(s);
//}
listener.Prefixes.Add("http://*:1234/"); // accept connections from everywhere,
//because the printer is accessible only within the LAN (no portforwarding)
listener.Start();
Console.WriteLine("Listening...");
// Note: The GetContext method blocks while waiting for a request.
HttpListenerContext context;
string urlForRequest = "";
HttpWebRequest requestForPage = null;
HttpWebResponse responseForPage = null;
string responseForPageAsString = "";
while (true)
{
context = listener.GetContext();
HttpListenerRequest request = context.Request;
urlForRequest = request.RawUrl.Substring(1, request.RawUrl.Length - 1); // remove the slash, which separates the portNumber from the arg sent
Console.WriteLine(urlForRequest);
//Request for the html page:
requestForPage = (HttpWebRequest)WebRequest.Create(urlForRequest);
responseForPage = (HttpWebResponse)requestForPage.GetResponse();
responseForPageAsString = new StreamReader(responseForPage.GetResponseStream()).ReadToEnd();
// Obtain a response object.
HttpListenerResponse response = context.Response;
// Send back the response.
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseForPageAsString);
// Get a response stream and write the response to it.
response.ContentLength64 = buffer.Length;
response.AddHeader("Access-Control-Allow-Origin", "*"); // the magic header in action ;-D
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
//listener.Stop();
All the user needs to do is run that console app as Admin. I know it is way too ... frustrating and complicated, but it is sort of a workaround to the Domain Policy problem in case you cannot modify the server in any way.
edit: from js I make a simple ajax call:
$.ajax({
type: 'POST',
url: 'http://LAN_IP:1234/http://google.com',
success: function (data) {
console.log("Success: " + data);
},
error: function (e) {
alert("Error: " + e);
console.log("Error: " + e);
}
});
The html of the requested page is returned and stored in the data variable.
To get the data form external site by passing using a local proxy as suggested by jherax you can create a php page that fetches the content for you from respective external url and than send a get request to that php page.
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost/get_url_content.php',false);
if(req.status == 200) {
alert(req.responseText);
}
as a php proxy you can use https://github.com/cowboy/php-simple-proxy
Your URL doesn't work these days, but your code can be updated with this working solution:
var url = "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P#ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute";
url = 'https://google.com'; // TEST URL
$.get("https://images"+~~(Math.random()*33)+"-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=" + encodeURI(url), function(data) {
$('div.ajax-field').html(data);
});
<div class="ajax-field"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You need CORS proxy which proxies your request from your browser to requested service with appropriate CORS headers. List of such services are in code snippet below. You can also run provided code snippet to see ping to such services from your location.
$('li').each(function() {
var self = this;
ping($(this).text()).then(function(delta) {
console.log($(self).text(), delta, ' ms');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/jdfreder/pingjs/c2190a3649759f2bd8569a72ae2b597b2546c871/ping.js"></script>
<ul>
<li>https://crossorigin.me/</li>
<li>https://cors-anywhere.herokuapp.com/</li>
<li>http://cors.io/</li>
<li>https://cors.5apps.com/?uri=</li>
<li>http://whateverorigin.org/get?url=</li>
<li>https://anyorigin.com/get?url=</li>
<li>http://corsproxy.nodester.com/?src=</li>
<li>https://jsonp.afeld.me/?url=</li>
<li>http://benalman.com/code/projects/php-simple-proxy/ba-simple-proxy.php?url=</li>
</ul>
Figured it out.
Used this instead.
$('.div_class').load('http://en.wikipedia.org/wiki/Cross-origin_resource_sharing #toctitle');
Problem:
Uncaught SyntaxError: Unexpected token <
What I tried
Request: Jsonp
Response: returned XML Response 200.
Cross Domain Request that's why used data type: jsonp
Script code:
$.ajax({
url: "some url",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
type: "POST", /* or type:"GET" or type:"PUT" */
data:myusername,
crossDomain: true,
dataType: 'jsonp',
data: {
'name':myusername
},
success: function (result) {
console.log(result);
},
error: function () {
console.log("error");
}
//});
});
Here AJAX response is XML.
But can someone tell how can I solved unexpected token problem.
Response is XML.
solution i found is third party request
var urljson='cross-damin-url';
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' +
encodeURIComponent('select * from xml where url="' + urljson + '"') +
'&format=xml&callback=?';
$.getJSON(yql, function (data) {
console.log(data.results[0]);
});
Any suggestion is most welcome.
the problem is the line "dataType: 'jsonp'". Setting it this way the ajax call expect the result to be a jsonp (a json object wrapped as a params in a callback...) this is useful if you're doing a cross domain call (due to CORS). You have to set a "dataType: 'xml'"
Edit
considering the you have to do a CORS call, you have to change the output of the api, at least making something like
callbackName({value:'<your><xml>...</xml></your>'})
and parsing the xml from the string
"callbackName" is the name of a function or method declared in the page which make the ajax call and which will parse the json from the api... for instance something like:
function callbackName(result) {
console.log($.parseXML(result.value));
}
JSON and XML are arbitrarily nested data-interchange formats. You take a (well-formed) string and convert it to a data structure based on the rules of the format. Their similarities stop there.
So you can't just parse XML as JSON, they have different rules for turning a string (like that returned by an HTTP request) into a data structure. Which is why you're getting an error.
Parsing XML with an XML parser (like the one built into every browser) instead of a JSON parser will not throw an error.
But your actual problem is that it's a cross-domain resource and the browser (for good reason) won't let you. If you need a cross-domain resource and you don't control it and it doesn't have a CORS header you have a few options:
Beg the entity that controls the resource to add a CORS Header
Pipe the resource through your domain.
To expand on option 2:
Your page requests the resource from your webserver, your webserver makes an http request to the cross-origin resource, and then sends the result back to the browser.
About JSONP
JSONP was a hack invented before CORS to bypass the browser's security model. It was (meant) to be used by people who understood the risks, knew what they were doing and why. It involves potentially executing arbitrary third-party code on your page. Needless to say, that's bad.
Here's the issue. I'm extracting gmail contacts through an ajax call in javascript/jquery like this:
function getUserInfo() {
var xml_parse = "";
$.ajax({
url: SCOPE + '?max-results=9999&access_token=' + acToken
data: null,
success: function (resp) {
xml_parse = $.parseXML(resp);
callGmailHelperWebService(xml_parse);
},
dataType: "jsonp"
});
}
function callGmailHelperWebService(xml_parse) {
GmailHelperService.ConvertXMLToList(xml_parse, onSuccess, onFailed, null);
}
So, as you can see, if the initial ajax call is successful, i call a function which calls a web service that sits on the save server as my project (in fact, it's part of the project).
My web service (GmailHelperService) is wired up correctly, as I can definitely call it in other places (like right after this ajax call, for example). However, when I try to call it within the "success" portion of the ajax call, i get the following error:
Uncaught Error: SECURITY_ERR: DOM Exception 18
My theory is that this has something to do with cross-domain issues, but I can't understand why. And I certainly can't figure out how to fix this.
I'd appreciate any help.
JSONP is a data transfer method that involves sending your data in this format:
callback({"foo":"bar"});
As you can see, this is NOT xml. It is JSON wrapped in a callback method that will get executed when the request is done loading, thus allowing it to be cross-domain because it can be requested using a <script> tag.
You cannot simply change your dataType to JSONP and return xml, expecting it to work. XML != JSONP. You can however return XML in jsonp, for example, callback({"xml","... xml string here "}) but be mindful of quotes, all json keys and values must be wrapped in double quotes, inner-quotes need to be handled appropriately.
If your request is a same domain request (Same protocol, same subdomain, same domain, and same port,) then you can change your dataType to "XML" if you are returning XML. Otherwise, you need to either setup a proxy script to get the xml for you, or have your webservice return JSONP.
For example, the following urls are all considered cross-domain from each other.
http://example.com
http://www.example.com
https://example.com
https://www.example.com
http://example.com:8080
All of the above urls would be considered cross-domain, even if they are on the same server.
I am currently having difficulty using the Google weather API in JavaScript using Mootools.
I am using code like this:
var location = $('weather-location').value;
var req = new Request({
url: 'http://www.google.com/ig/api?weather=' + location,
method: 'get',
onSuccess: function(responseText, responseXML)
{
responseXML.getElements('forecast_information').each(function(item)
{
item.getElements('city').each(function(city_data)
{
$('placename').set('html','Weather for ' + city_data.get('data'));
});
});
}
}).send();
This code results in a browser error which is reported in Firebug as:
"NetworkError: 405 Method Not Allowed - http://www.google.com/ig/api?weather=72601&location=72601"
From what I can gather (I am rather new at this), this problem is caused by cross-domain access violation.
I have tried:
1) using 'post' instead of 'get' for method... similar result
2) using Request.HTML and Request.JSON instead of Request... similar result
3) using Request.JSONP ...different error (document formatting I think). I suspect this is because the google weather API returns straight XML and isn't set up to serve JSONP.
4) using YQL instead of a straight url to google (sample URL: http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D"http%3A%2F%2Fwww.google.com%2Fig%2Fapi%3Fweather%3DDenver%2520CO") ... this did not have an error but returned no results either (URL does work if typed into address of browser).
The only way I have been able to get this to work is to pull the weather XML server-side and serve it to the browser via a proxy. However, I am would like to accomplish this without burdening my server.
How can this be done?
It is a cross-domain issue. Stick to the solution you have (proxy). The browser is not allowed to do a request to 'google.com' when the actual page is located at 'yourdomain.com'.
So i have a json file named array.json on my web-server i intend to read this file in my web-application locally (for now) and then on a different domain once i go live, i have created this json file myself and here is the data it contains.
{"h1": "cmPanel", "h2" : "cmAuto", "h3": 0}
When i am trying to read the file I am not getting back a response, why would this be?
Here is my code for reading the file;
$.getJSON('http://www.foobar.com/array.json', function(data){
alert(data);
});
I have also tried adding &callback=? and still i receive nothing, could you please assist !
Quoting official docs:
Due to browser security restrictions, most "Ajax" requests are
subject to the same origin policy; the request can not successfully
retrieve data from a different domain, subdomain, or protocol.
Script and JSONP requests are not subject to the same origin
policy restrictions.
More info about Same Origin Policy
To work around it, look into JSONP.
In order to do cross-domain ajax calls you will either need to use a proxy or JSONP. Since you're setup for JSON already JSONP might be the easiest alternative. In short, JSONP entails wrapping your JSON data in a function call so it can be passed back to the calling script in a way that circumvents the Same Origin Policy.
In your case, you could wrap your json data with function named "myjsoncallback" so that it looks like this:
myjsoncallback({"h1": "cmPanel", "h2" : "cmAuto", "h3": 0})
And then change your ajax call to something like the following:
$.ajax({
url: 'http://www.foobar.com/array.json',
dataType: 'jsonp',
jsonpCallback: 'myjsoncallback', // Specify our callback function name
success: function(data) { console.log(data); }
});
Have you got access to the server from your web application? (same origin policy)
To use jsonp you could not simply add callback to the URL of the json file. The server should deliver a function that return the data. This file you could include with the default html script tag and execute the returned function afterwards.
To see the returned json you need to itterate the result
$.getJSON('array.json', function(data){
var items = [];
$.each(data, function(key, val) {
items.push('Key = ' + key + '<br/>Value = ' + val + '<br/><br/>');
});
alert(items.join(''));
});
array.json shoud be served with proper Content-Type:
text/javascript; charset=utf-8 if callback is used
application/json; charset=utf-8 if it is plain json
see here Best content type to serve JSONP?
to avoid problems from 'same origin policy'