12

我正在开发一个移动网络应用程序,jsonp 对于跨域请求非常酷,但是服务器的 API 不支持回调参数。所以我只能使用 json 从远程服务器获取数据。

我在 jQuery 中尝试了 json,似乎它不支持跨域请求。我在 safari 上尝试了 raw ajax 请求功能,它在跨域上运行良好,那么我可以消除 jQuery 中对 json 请求的跨域限制吗?(不是jsonp,只有json),怎么做?

或者是否有任何替代的简单 ajax 库(跨网络浏览器)并且可以对跨域请求执行 json。

4

3 回答 3

33

同源政策

您正试图规避Same Origin Policy。它内置于每个浏览器中,通常不是您可以或不应该想要禁用/解决方法/等的东西。它是您的站点、用户和用户浏览器之间非常重要的安全契约。

CORS(可能)

CORS允许您的 Web 服务器告诉浏览器/客户端访问另一个域是允许的。这是通过您的 Web 服务器输出以下 HTTP 标头来完成的

 Access-Control-Allow-Origin: http://www.example.com

如果你不能控制你的 HTTP 标头,那么你就不能使用 CORS。实现这一点是特定于语言/框架的。

请注意,您应该检查以确保浏览器兼容性,因为 IE8/9 支持有限。另请注意,这是一个潜在的攻击媒介。如果您不负责任地使用响应数据,它允许来自 3rd 方站点的响应执行 XSS 攻击。

JSONP(可能)

JSONP是一种在服务器之间传递和获取数据的巧妙方法,它通过动态添加一个属性等于您的页面的script标签 。这是在没有 Web 代理(见下文)或小程序(Flash/Java)的情况下完成这一壮举的唯一合法方式。但是,如果您不是请求两端的提供者,它确实有其自身的安全风险。请记住,JSONP 允许远程服务器在您的上下文中执行代码,您应该非常小心将这种权力授予谁src"yoururl.com?<your parameter data>"

“香草”AJAX(不可能)

如果您没有使用 JSONP 来获取数据,那么您很可能会尝试使用 AJAX 请求来获取数据。AJAX 请求也受同源策略的约束。JavaScript 库(例如 jQuery、Prototype、Dojo 等)无法绕过此策略作为 Ajax 请求的基本行为。但是,它们可以支持 JSONP(现在记住,它不是 AJAX)。

带 Web 代理的 AJAX(可能)

如果您确实想从另一台服务器请求数据,您可以转发您的请求。您的主站点的服务器将充当代理。您需要向您自己的服务器发出 AJAX 请求,然后该服务器端代码将向另一个域发出请求,然后通过 AJAX 调用响应将响应发送到您的脚本。

这是一种常见的模式,在这里详细描述为Web 代理模式和对界面友好的 Yahoo模式(但请记住,它是 Yahoo 特定的,只接受一般概念)。但是,它取决于服务器端语言。整体实现将是相同的,但是执行此操作的代码将根据您选择的服务器端语言(PHP、Ruby、Python、C 等)而有所不同。一些语言已经有库/模块/等来支持这种模式。

Flash(可能,非默认)

默认状态下的 Flash 不支持跨域请求。它可以在 Flash7+ 中使用跨域策略文件打开,但强烈建议不要。您的脚本必须与 Flash API 交互,以便发出请求并将数据返回到您的 JavaScript。

Java Applet(可能,非默认)

Java 也受制于同源策略,但与 Flash 有类似的工作,如其发布中所述

其他各种“黑客”

那里还有其他黑客,但它们通常要求您控制两端或有一个商定的通信标准。例如'window.name' hack。我不建议大多数这些方法。

其他解决方案

另一个类似的问题被问到了。它概述了我没有介绍的其他一些方法:绕过同源策略的方法

最佳解决方案

  1. CORS - 如果您信任第 3 方
  2. 网络代理——如果你不这样做

您自己域上的网络代理可以让您清理正在检索的数据,它为您的用户提供最大的保护。但是,如果您进行零卫生,它并不比此处概述的任何方法更安全。如果您确实实施了某种网络代理,请确保其请求仅限于您希望的站点。否则,您实际上将创建一个开放代理,如果发现它可能会被用户滥用并使您陷入法律麻烦。

于 2012-07-02T19:00:49.547 回答
6

我遇到过同样的问题。试图从服务器获取 json 到我无法访问的地方(=> 没有 JSONP)。

我找到http://benalman.com/projects/php-simple-proxy/将 php 代理添加到您的服务器并对这个文件进行 ajax 调用。“任何要传递到远程 URL 资源的 GET 参数都必须在此参数中进行 urlencoded。”

$.ajax({
   type: 'GET',
   url:'proxy.php?url=http://anyDomain.com?someid=thispage',
   dataType: "json",
   success: function(data){
      // success_fn(data);
   },
   error: function(jqXHR, textStatus, errorThrown) {
      // error_fn(jqXHR, textStatus, errorThrown);
   }
});

proxy.php(来自 Ben Alman 的文件)托管在您的域中


替代方案(我发现这是第二好的):http: //james.padolsey.com/javascript/cross-domain-requests-with-jquery/

于 2012-07-23T02:17:24.100 回答
4

一种相当俗气的做法是我在下面所做的,以在个人项目上启用跨站点执行

请注意,这将在接收服务器而不是发送服务器上完成

    if ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') === FALSE)
        die('You shouldn\'t be here');

    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
    header('Access-Control-Max-Age: 1000');
    header('Access-Control-Allow-Headers: Content-Type');

如果你想让它更安全一点,你可以这样做

    if ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') === FALSE)
        die('You shouldn\'t be here');

switch($_SERVER['HTTP_ORIGIN']){
case 'domain.com':
case 'whatever.com':
        header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
        header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
        header('Access-Control-Max-Age: 1000');
        header('Access-Control-Allow-Headers: Content-Type');
}

希望这会有所帮助,我花了很长时间才弄清楚哈哈。

于 2012-07-02T19:05:53.087 回答