views:

701

answers:

8

Hi Folks,

I know about ajax cross-domain policy. So I can't just call "http://www.google.com" over a ajax HTTP request and display the results somewhere on my site.

I tried it with dataType "jsonp", that actually would work, but I get a syntax error (obviously because the received data is not json formated)

Is there any other possiblity to receive/display data from a foreign domain ? iFrames follow the same policy?

Kind Regards

--Andy

+2  A: 

You will need to dynamically insert a script tag into the page that references the data. Using JSONP, you can execute some callback function when the script has loaded.

The wikipedia page on JSONP has a concise example; the script tag:

<script type="text/javascript" src="http://domain1.com/getjson?jsonp=parseResponse"&gt;
</script>

would return the JSON data wrapped in a call to parseResponse:

parseResponse({"Name": "Cheeso", "Rank": 7})

(depending on the configuration of the getjson script on domain1.com)

The code to insert the tag dynamically would be something like:

var s = document.createElement("script");
s.src = "http://domain1.com/getjson?jsonp=parseResponse";
s.type = "text/javascript";
document.appendChild(s);
alunny
would this only work if you receive JSON data or with plain text or HTML aswell?
jAndy
@jAndy: This will work for JSONP (including the callback function) data only.
Andy E
A: 

JSONP is the best option, in my opinion. Try to figure out why you get the syntax error - are you sure the received data is not JSON? Then maybe you're using the API wrong somehow.

Another way you could use, but I don't think that it applies in your case, is have an iFrame in the page which src is in the domain you want to call. Have it do the calls for you, and then use JS to communicate between the iFrame and the page. This will bypass the cross domain, but only if you can have the iFrame's src in the domain you want to call.

Nir
@Nir: He gets the syntax error because he's fetching HTML, not JSON. This will never work with JSONP :-)
Andy E
+2  A: 

Unfortunately (or fortunately) not. The cross-domain policy is there for a reason, if it were easy to get around it then it wouldn't be very effective as a security measure. Other than JSONP, the only option is to proxy the pages using your own server.

With an iframe, they are subject to the same policy. Of course you can display the data from an external domain, you just can't manipulate it.

Andy E
what do you mean by, "you just can't manipulate it" ?You can't load some data into an iFrame and read that data over a jQuery selector for instance?
jAndy
@jAndy: No, access is blocked to 99% of the DOM when accessing documents across different domains. Cross-document messaging is possible (with HTML5/modern browsers), but it has to be implemented by both sides.
Andy E
+1  A: 

The only (easy) way to get cross-domain data using AJAX is to use a server side language as the proxy as Andy E noted. Here's a small sample how to implement that using jQuery:

The jQuery part:

$.ajax({
    url: 'proxy.php',
    type: 'POST',
    data: {
        address: 'http://www.google.com'
    },
    success: function(response) {
        // response now contains full HTML of google.com
    }
});

And the PHP (proxy.php):

echo file_get_contents($_POST['address']);

Simple as that. Just be aware of what you can or cannot do with the scraped data.

Tatu Ulmanen
And be very much aware that such a proxy is a severe security hole... At least make a list of acceptable addresses and don't just blindly accept any passed address.Have a look at a decent proxy script here: http://benalman.com/projects/php-simple-proxy/
christian studer
A: 

after doing some research, the only "solution" to this problem is to call:

if($.browser.mozilla)
   netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');

this will ask an user if he allows a website to continue. After he confirmed that, all ajax calls regardless of it's datatype will get executed.

This works for mozilla browsers, in IE < 8, an user has to allow a cross domain call in a similar way, some version need to get configured within browser options.

chrome/safari: I didn't find a config flag for those browsers so far.

using JSONP as datatype would be nice, but in my case I don't know if a domain I need to access supports data in that format.

Another shot is to use HTML5 postMessage which works cross-domain aswell, but I can't afford to doom my users to HTML5 browsers.

Kind Regards

--Andy

jAndy
@jAndy, you are not dooming your users to HTML5 browsers, you are making them a service :-)
Darin Dimitrov
A: 

If you have access to the other domain you're making the request to then you can use Flash to make cross-domain requests. This obviously won't work for sites like google.

dlongley
A: 

I faced the same problem during 2 days and I found the solution, and it's elegant after googling a lot. I needed xss Ajax for some widget clients which pull datastream from tiers websites to my Rails app. here's how I did.

R Francky
A: 

I use this code for cross domain ajax call, I hope it will help more than one here. I'm using Prototype library and you can do the same with JQuery or Dojo or anything else:

Step 1: create a new js file and put this class inside, I called it xss_ajax.js

var WSAjax = Class.create ({ initialize: function (_url, _callback){ this.url = _url ; this.callback = _callback ; this.connect () ; }, connect: function (){ var script_id = null; var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', this.url); script.setAttribute('id', 'xss_ajax_script');

    script_id = document.getElementById('xss_ajax_script');
    if(script_id){
        document.getElementsByTagName('head')[0].removeChild(script_id);
    }

    // Insert <script> into DOM
    document.getElementsByTagName('head')[0].appendChild(script);
},
process: function (data){
    this.callback(data) ;
}

}) ;

This class creates a dynamic script element which src attributes targets your JSON data provider (JSON-P in fact as your distant server must provide the data in this format :: call_back_function(//json_data_here) :: so when the script tag is created your JSON will be directly evaled as a function (we'll talk about passing the callback method name to server on step 2), the main concept behind this is that script like img elements are not concerned by the SOP constraints.

Step2: in any html page where you wanna pull the JSON asynchronously (we call this AJAJ ~ Asynchronous JAvascript + JSON :-) instead of AJAX which use the XHTTPRequest object) do like below

//load Prototype first //load the file you've created in step1

var xss_crawler = new WSAjax ("http://your_json_data_provider_url?callback=xss_crawler.process", function (_data){ // your json data is _data and do whatever you like with it }) ;

D'you remenber the callback on step 1? so we pass it to the server and it will returns the JSON embeded in that method so in our case the server will return an evalable javascript code xss_crawler.process(//the_json_data), remember that xss_crawler is an instance of WSAjax class. The server code depends on you (if it's yours), but most of Ajax data providers let you specify the callback method in parameters like we did. In Ruby on rails I just did

render :json=>MyModel.all(:limit=>10), :callback => params[:callback],:content_type => "application/json"

and that's all, you can now pull data from another domain from your apps (widgets, maps etc), in JSON format only, don't forget.

I hope it was helpfull, thanks for your patience :-), peace and sorry for code formatting, it doesn't work well

R Francky