【问题标题】:Substitute for Cross-domain request with JavaScript用 JavaScript 代替跨域请求
【发布时间】:2011-05-26 12:27:56
【问题描述】:

我在名为 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 格式的日历,它会定期更改。我在共享主机上,没有系统管理员权限,但我可以运行 PHP 和 CGI​​ 脚本,并且可以更改 .htaccess 文件的某些部分。

【问题讨论】:

标签: php javascript ajax .htaccess cgi


【解决方案1】:

一些选项:

  1. 如果您可以控制服务器并且您的用户将使用最新的网络浏览器,您可以使用CORS。遗憾的是,IE7 或更低版本不支持 CORS。在 IE8 中,它就在那里,但您必须使用 XDomainRequest 而不是 XMLHttpRequest(其他浏览器,如 Chrome 和 Firefox,使用 XMLHttpRequest 完全透明地处理 CORS)。
  2. 如果没有,您可以使用JSONP,它适用于所有浏览器。
  3. 您可以使用document.domain 来指定这两个页面(如果它们确实是同一science.net 域的子域)位于同一来源。这在浏览器中运行良好,但它的缺点是您必须先将目标文档加载到窗口(可能是隐藏的 iframe)中才能访问它,因为目标文档 also 必须设置document.domain(表示想和你合作)。
  4. 对于公共内容,另一种选择是using YQL as a proxy
  5. 如果所有这些都失败了,您唯一真正的选择是在您查询的服务器上安装一个代理脚本,然后使用 服务器端 代码从其他域查询资源(因为此限制仅适用于客户端)。

这些是按我使用它们的大致顺序列出的。例如,如果您控制服务器并且知道您的客户端将使用最新的浏览器,则使用 CORS;如果没有,请查看 JSONP(尽管从您下面的评论来看,您可能不能);如果不是其中任何一个,也许document.domain 就是答案;等等,等等,将列表向下推到最后的选项(代理)。

【讨论】:

  • JSONP 是否要求文件 galileo.science.net/calendar 为 JSON 格式?不幸的是,事实并非如此,而且我无法控制。
  • @Heinrich:是的。使用 JSONP,您请求的基本上是一个脚本文件,并且必须以特定方式设置。如果您无法控制您请求的内容,您将查看选项#1(document.domain,如果它们确实是同一域的子域),#2(CORS,如果服务器允许任何来源)、选项 4 或新添加的选项 5。
  • 你能举例说明如何使用document.domain吗?只需在 JavaScript 中添加document.domain = "science.net"
  • @Heinrich:是的,就是这么简单。 MDC 页面上的更多(无论如何,一点点):developer.mozilla.org/en/document.domain 请注意,必须在 两个 页面上完成,表明他们有合作的意图。这要求您将计划连接的 HTML 加载到 iframe 或其他东西中,而不是通过 XHR。
  • 我不得不承认我忘记了双方必须做document.domain的事情。我已经在列表中降级了。 :-)
【解决方案2】:

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

但您可以使用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)。

【讨论】:

  • 很遗憾,我访问的文件不是 JSON 格式的。我无法控制它。
  • 那么 json-p 是行不通的(但你可以自己代理它?)。或者你也可以使用 YQL 跨域请求 => developer.yahoo.com/yql。 YQL 将为您做代理。
【解决方案3】:

假设您可以在 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
    }
}

【讨论】:

  • 这看起来像是一个解决方案。您能否详细说明一下缓存机制,假设它只需要几行 PHP 代码?
【解决方案4】:

使用JSONP。在javascript中,在以其他服务器的接口为源的页面中嵌入一个新的脚本元素。

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

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • 我无法控制galileo.science.net上的文件格式。
    猜你喜欢
    • 2019-04-02
    • 2012-02-26
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 2023-03-12
    • 2012-05-12
    • 1970-01-01
    相关资源
    最近更新 更多