简体   繁体   中英

Substitute for Cross-domain request with JavaScript

I have a JavaScript on a server named kopernikus.science.net that wants to access a file on a different server named galileo.science.net . Here a toy example of what I have in mind:

code residing on  http://kopernikus.science.net/makecalendar.js :

    var request = new XMLHttpRequest();
    request.open("GET","galileo.science.net/calendar", false);
    request.send(null);
    document.getElementById("calendar").innerHTML =
        "<div>" + request.responseText.split('\n')[0] + "</div>";

Unfortunately, due to the "same origin policy" of modern web browsers, the script is forbidden from accessing the data on a different domain.

Of course, my question is:

How can I access the remote file anyway?

Solutions outside JavaScript are allowed, like mirroring the file in question or tweaking .htaccess . What are my options? Which require the least amount of permissions on the web server?

The file in question is a calendar in vcalendar format which changes regularly. I'm on a shared host and don't have sysadmin rights, but I can run PHP and CGI scripts and can change some parts of the .htaccess file.

Some options:

  1. If you're in control of the servers and your users will be using an up-to-date web browser, you can use CORS . Sadly, there is no CORS support in IE7 or below. In IE8, it's there, but you have to use an XDomainRequest instead of an XMLHttpRequest (other browsers, like Chrome and Firefox, handle CORS completely transparently with XMLHttpRequest ).
  2. If not, you can use JSONP , which works with all browsers.
  3. You can use document.domain to specify that both of those pages (if they're really subdomains of the same science.net domain) are in the same origin. That works well across browsers, but it has the disadvantage that you first have to load the target document into a window (probably a hidden iframe) before you can access it, because the target document also has to set document.domain (to show that it wants to cooperate with you).
  4. Another alternative, for public stuff, is using YQL as a proxy .
  5. If all of those fail, your only real option is to have a proxy script on your server that you query, which then uses server-side code to query the resource from the other domain (since this restriction only applies client-side).

Those are listed in roughly the order in which I would use them. Eg, use CORS if you control the servers and know your clients will be using up to date browsers; if not, look at JSONP (although from your comment below, you probably can't); if not either of those, perhaps document.domain is the answer; etc., etc., working down the list to the option of last resort (proxying).

Unfortunately, due to the "same origin policy" of modern web browsers, the script is forbidden from accessing the data on a different domain.

But what you could do is use json-p .

Script and JSONP requests are not subject to the same origin policy restrictions.

<!DOCTYPE html>
<html>
<head>
  <style>img{ height: 100px; float: left; }</style>
  <script src="http://code.jquery.com/jquery-1.4.4.js"></script>
</head>
<body>
  <div id="images">

</div>
<script>
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?",
  {
    tags: "cat",
    tagmode: "any",
    format: "json"
  },
  function(data) {
    $.each(data.items, function(i,item){
      $("<img/>").attr("src", item.media.m).appendTo("#images");
      if ( i == 3 ) return false;
    });
  });</script>

</body>
</html>

As a side note the modern browser support CORS (Internet Explorer 8+, Firefox 3.5+, Safari 4+, and Chrome).

Assuming you can deploy PHP on kopernikus.science.net, why not just proxy it there...

<?php
header('Content-Type: application/x-javascript');
print file_get_contents('http://galileo.science.net/calendar');

(and of course you could potentially cache it briefly on the proxy and client to cut down on network noise)

Update

If you want to cache....

<?php
header('Content-Type: application/x-javascript');
define("CACHEDIR", '/tmp/webcache/');
$cache_time=14 * 24 * 60 * 60; // cache for 2 weeks
$key=sha1('http://galileo.science.net/calendar');

if (@filemtime(CACHEDIR . $key) > time() - $cache_time) { // cache good
    print file_get_contents(CACHEDIR . $key);
} else {  // cache stale
    $freshcopy=file_get_contents('http://galileo.science.net/calendar');
    print $freshcopy;
    if (!file_put_contents(CACHEDIR . $key, $freshcopy)) {
       // report a problem writing files
    }
}

Use JSONP . In the javascript, embed a new script element in the page that has the interface of the other server as source.

The server should return something like this:

callCallback({"some":"JSONString"});

This is a very known problem and JSONP is solution of the problem. You can google and fine a tons of information on that. You might consider this as example of usage JSONP with and without jQuery.

http://www.beletsky.net/2010/07/json-jsonp-and-same-origin-policy-issue.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM