【问题标题】:AJAX cross domain callAJAX跨域调用
【发布时间】:2011-02-03 06:39:51
【问题描述】:

我知道 AJAX 跨域策略。 所以我不能只通过 ajax HTTP 请求调用“http://www.google.com”并显示 我网站上某处的结果。

我用dataType“jsonp”试了一下,确实可以,但是我得到一个语法错误(显然是因为接收到的数据不是JSON格式的)

还有其他可能接收/显示来自外国域的数据吗? iFrame 遵循相同的政策?

【问题讨论】:

    标签: javascript jquery ajax json jsonp


    【解决方案1】:

    使用 AJAX 获取跨域数据的唯一(简单)方法是使用服务器端语言作为代理,如 Andy E 所述。这是一个如何使用 jQuery 实现的小示例:

    jQuery部分:

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

    还有PHP(proxy.php):

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

    就这么简单。请注意您可以对抓取的数据做什么或不能做什么。

    【讨论】:

    • 并且要非常清楚,这样的代理是一个严重的安全漏洞......至少列出可接受的地址,不要盲目地接受任何传递的地址。在这里查看一个不错的代理脚本:benalman.com/projects/php-simple-proxy
    • 但是当目标页面有非绝对URL和相对链接时,它不会破坏布局吗?
    • @ChristianStuder 为什么会有问题?
    【解决方案2】:

    您需要将脚本标签动态插入到引用数据的页面中。使用 JSONP,您可以在脚本加载后执行一些回调函数。

    JSONP 上的维基百科页面有一个简洁的例子;脚本标签:

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

    将返回封装在对 parseResponse 的调用中的 JSON 数据:

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

    (取决于 domain1.com 上getjson 脚本的配置)

    动态插入标签的代码如下:

    var s = document.createElement("script");
    s.src = "http://domain1.com/getjson?jsonp=parseResponse";
    s.type = "text/javascript";
    document.appendChild(s);
    

    【讨论】:

    • 仅当您收到 JSON 数据或纯文本或 HTML 数据时,这是否有效?
    • @jAndy:这仅适用于 JSONP(包括回调函数)数据。
    • 仅适用于 GET 请求。没有 PUT、DELETE 或 POST。所以没有 RESTful 接口。
    【解决方案3】:

    您可以使用YQL 来执行请求,而无需托管您自己的代理。我做了一个简单的函数,让运行命令更容易:

    function RunYQL(command, callback){
         callback_name = "__YQL_callback_"+(new Date()).getTime();
         window[callback_name] = callback;
         a = document.createElement('script');
         a.src = "http://query.yahooapis.com/v1/public/yql?q="
                 +escape(command)+"&format=json&callback="+callback_name;
         a.type = "text/javascript";
         document.getElementsByTagName("head")[0].appendChild(a);
    }
    

    如果你有 jQuery,你可以使用 $.getJSON 代替。

    一个样本可能是这样的:

    RunYQL('select * from html where url="http://www.google.com/"',
           function(data){/* actions */}
    );
    

    【讨论】:

      【解决方案4】:

      不幸(或幸运)没有。跨域策略的存在是有原因的,如果它很容易绕过它,那么它作为一种安全措施就不会非常有效。除了 JSONP,唯一的选择是proxy the pages using your own server。

      对于 iframe,它们需要遵守相同的政策。当然,您可以显示来自外部域的数据,只是不能对其进行操作。

      【讨论】:

      • 你说的“你就是不能操纵它”是什么意思?例如,您不能将某些数据加载到 iFrame 中并通过 jQuery 选择器读取该数据?
      • @jAndy:不,当访问不同域的文档时,对 99% 的 DOM 的访问被阻止。跨文档消息传递是可能的(使用 HTML5/现代浏览器),但必须由双方实现。
      【解决方案5】:

      我将此代码用于跨域 ajax 调用,我希望它对这里的帮助不止一个。我正在使用 Prototype 库,您可以使用 JQuery 或 Dojo 或其他任何东西来做同样的事情:

      第一步:新建一个js文件,把这个类放在里面,我叫它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) ;
          }
      
      }) ;
      

      这个类创建一个动态脚本元素,它的 src 属性针对您的 JSON 数据提供者(JSON-P 实际上因为您的远程服务器必须以这种格式提供数据 :: call_back_function(//json_data_here) :: 所以当脚本标签创建后,您的 JSON 将直接作为函数进行评估(我们将在步骤 2 中讨论将回调方法名称传递给服务器),这背后的主要概念是 img 元素之类的脚本不受 SOP 约束。

      Step2:在任何你想异步拉取 JSON 的 html 页面中(我们称之为 AJAJ ~ Asynchronous JAvascript + JSON :-) 而不是使用 XHTTPRequest 对象的 AJAX),如下所示

      //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 
              }) ;
      

      你还记得第 1 步的回调吗?所以我们将它传递给服务器,它将返回嵌入在该方法中的 JSON,因此在我们的例子中,服务器将返回一个可评估的 JavaScript 代码 xss_crawler.process(//the_json_data),请记住 xss_crawler 是 WSAjax 类的一个实例。服务器代码取决于您(如果它是您的),但大多数 Ajax 数据提供程序允许您像我们一样在参数中指定回调方法。 我刚刚在 Ruby on rails 中做了

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

      仅此而已,您现在可以从您的应用程序(小部件、地图等)中提取来自另一个域的数据,仅限 JSON 格式,不要忘记。

      希望对您有所帮助,感谢您的耐心等待 :-),对代码格式化表示抱歉,它不能正常工作

      【讨论】:

        【解决方案6】:

        在做了一些研究之后,这个问题的唯一“解决方案”是调用:

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

        这将询问用户是否允许网站继续运行。在他确认之后,所有 无论数据类型如何,ajax 调用都会被执行。

        这适用于 mozilla 浏览器,在 IE

        chrome/safari:到目前为止,我还没有找到这些浏览器的配置标志。

        使用 JSONP 作为数据类型会很好,但在我的情况下,我不知道我是否需要一个域 访问支持该格式的数据。

        另一种方法是使用 HTML5 postMessage,它也可以跨域工作,但我不能 让我的用户只能使用 HTML5 浏览器。

        【讨论】:

        • 您并没有让您的用户使用 HTML5 浏览器,而是让他们成为一种服务 :-)
        【解决方案7】:

        如果您使用 php 脚本从远程服务器获取答案,请在开头添加以下行:

        header("Access-Control-Allow-Origin: *");
        

        【讨论】:

          【解决方案8】:

          在我看来,JSONP 是最好的选择。尝试找出为什么会出现语法错误 - 你确定接收到的数据不是 JSON 吗?那么也许你以某种方式错误地使用了 API。

          您可以使用的另一种方式,但我认为它不适用于您的情况,即在页面中有一个 iFrame,其中 src 位于您要调用的域中。让它为你做调用,然后使用 JS 在 iF​​rame 和页面之间进行通信。这将绕过跨域,但前提是您可以在要调用的域中拥有 iFrame 的 src。

          【讨论】:

          • @Nir:他得到了语法错误,因为他正在获取 HTML,而不是 JSON。这永远不会与 JSONP 一起工作 :-)
          【解决方案9】:

          这是一种简单的方法,无需使用任何花哨的东西,甚至是 JSON。

          首先,创建一个服务器端脚本来处理您的请求。类似http://www.example.com/path/handler.php

          您将使用参数调用它,如下所示:.../handler.php?param1=12345&param2=67890

          在里面,处理接收到的数据后,输出:

          document.serverResponse('..all the data, in any format that suits you..');
          // Any code could be used instead, because you dont have to encode this data
          // All your output will simply be executed as normal javascript
          

          现在,在客户端脚本中,使用以下内容:

          document.serverResponse = function(param){ console.log(param) }
          
          var script = document.createElement('script');
          script.src='http://www.example.com/path/handler.php?param1=12345&param2=67890';
          document.head.appendChild(script);
          

          这种方法的唯一限制是您可以发送到服务器的参数的最大长度。但是,您始终可以发送多个请求。

          【讨论】:

            【解决方案10】:

            您可以使用 CORS 技术来配置两个服务器(运行 Javascript 的服务器和外部 API 服务器)

            https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

            p.s.:https://stackoverflow.com/a/37384641/6505594 的答案也是在建议这种方法,它正在向其他人开放外部 API 服务器来调用它。

            【讨论】:

              【解决方案11】:

              我在 2 天内遇到了同样的问题,我找到了解决方案,并且在谷歌上搜索了很多之后它很优雅。 我需要一些小部件客户端的 xss Ajax,这些客户端将数据流从层级网站拉到我的 Rails 应用程序。 here's how I did.

              【讨论】:

                猜你喜欢
                • 2010-10-13
                • 1970-01-01
                • 1970-01-01
                • 2012-02-08
                • 2013-03-15
                • 1970-01-01
                • 1970-01-01
                • 2012-08-27
                • 2013-12-07
                相关资源
                最近更新 更多