用JavaScript代替跨域请求

时间:2010-12-16 11:53:35

标签: php javascript ajax .htaccess cgi

我在名为kopernikus.science.net的服务器上有一个JavaScript,它希望访问名为galileo.science.net的其他服务器上的文件。这是我想到的一个玩具示例:

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>";

不幸的是,由于现代网络浏览器的“同源策略”,禁止脚本访问不同域的数据。

当然,我的问题是:

  

我怎样才能访问远程文件?

     

允许JavaScript之外的解决方案,例如镜像相关文件或调整.htaccess。我有什么选择?哪个需要Web服务器上的权限最少?

有问题的文件是vcalendar格式的日历,会定期更改。我在共享主机上,没有sysadmin权限,但我可以运行PHP和CGI脚本,可以更改.htaccess文件的某些部分。

5 个答案:

答案 0 :(得分:8)

一些选项:

  1. 如果您控制服务器并且您的用户将使用最新的Web浏览器,则可以使用CORS。遗憾的是,IE7或更低版​​本中没有CORS支持。在IE8中,它就在那里,但你必须使用XDomainRequest而不是XMLHttpRequest(其他浏览器,如Chrome和Firefox,使用XMLHttpRequest完全透明地处理CORS。)
  2. 如果没有,您可以使用适用于所有浏览器的JSONP
  3. 您可以使用document.domain指定这两个页面(如果它们实际上是同一个science.net域的子域)位于同一个源中。这在浏览器中运行良好,但它的缺点是您首先必须将目标文档加载到窗口(可能是隐藏的iframe)才能访问它,因为目标文档必须设置document.domain(表明它希望与您合作)。
  4. 对于公共内容,另一种选择是using YQL as a proxy
  5. 如果所有这些都失败了,您唯一真正的选择是在您查询的服务器上有一个代理脚本,然后使用服务器端代码从另一个域查询资源(因为此限制仅适用于客户端)。
  6. 大致按照我使用它们的顺序列出。例如,如果您控制服务器并且知道您的客户将使用最新的浏览器,则使用CORS;如果没有,请查看JSONP(虽然从下面的评论中,你可能不能);如果不是其中任何一个,也许document.domain就是答案;等等,在列表中工作到最后的选择(代理)。

答案 1 :(得分:1)

  

不幸的是,由于“相同的起源   现代网络浏览器的政策,   脚本被禁止访问   不同域名的数据。

但你可以做的是使用json-p

  

脚本和JSONP请求不是   受同一原产地政策约束   限制。

<!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>

作为旁注,现代浏览器支持CORS(Internet Explorer 8 +,Firefox 3.5 +,Safari 4+和Chrome)。

答案 2 :(得分:1)

假设您可以在kopernikus.science.net上部署PHP,为什么不在那里代理它...

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

(当然,您可以在代理和客户端上暂时缓存它以减少网络噪音)

<强>更新

如果你想缓存....

<?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
    }
}

答案 3 :(得分:0)

使用JSONP。在javascript中,在页面中嵌入一个新的脚本元素,该页面具有另一个服务器的接口作为源。

服务器应该返回如下内容:

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

答案 4 :(得分:0)

这是一个众所周知的问题,JSONP是问题的解决方案。你可以google并提供大量的信息。您可以将此视为使用JSONP和使用jQuery的示例。

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