首页 文章

用外行人的话可以解释一下JSONP是什么吗? [重复]

提问于
浏览
405

这个问题在这里已有答案:

我知道 JSONP 是带有填充的 JSON .

我理解JSON是什么,以及如何将它与jQuery.getJSON()一起使用 . 但是,在介绍JSONP时,我不理解 callback 的概念 .

任何人都可以向我解释这是如何工作的?

4 回答

  • 759

    前言:

    这个答案已有六年多了 . 虽然JSONP的概念和应用没有改变(即答案的细节仍然有效),但你应该look to use CORS where possible(即你的serverAPI支持它,browser support就足够了),如JSONP has inherent security risks .


    JSONP(带填充的JSON)是一种常用于绕过Web浏览器中的跨域策略的方法 . (您不允许向浏览器认为位于不同服务器上的网页发出AJAX请求 . )

    JSON和JSONP在客户端和服务器上的行为不同 . 不使用 XMLHTTPRequest 和关联的浏览器方法调度JSONP请求 . 而是创建 <script> 标记,其源设置为目标URL . 然后将此脚本标记添加到DOM(通常在 <head> 元素内) .

    JSON请求:

    var xhr = new XMLHttpRequest();
    
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        // success
      };
    };
    
    xhr.open("GET", "somewhere.php", true);
    xhr.send();
    

    JSONP请求:

    var tag = document.createElement("script");
    tag.src = 'somewhere_else.php?callback=foo';
    
    document.getElementsByTagName("head")[0].appendChild(tag);
    

    JSON响应和JSONP响应之间的区别在于JSONP响应对象作为参数传递给回调函数 .

    JSON:

    { "bar": "baz" }
    

    JSONP:

    foo( { "bar": "baz" } );
    

    这就是您看到包含 callback 参数的JSONP请求的原因,以便服务器知道包装响应的函数的名称 .

    在浏览器评估 <script> 标记时(请求完成后),此函数必须存在于全局范围内 .


    处理JSON响应和JSONP响应之间需要注意的另一个区别是,JSON响应中的任何解析错误都可以通过包装尝试在try / catch语句中评估responseText来捕获 . 由于JSONP响应的性质,响应中的解析错误将导致无法捕获的JavaScript解析错误 .

    两种格式都可以通过在启动请求之前设置超时并在响应处理程序中清除超时来实现超时错误 .


    使用jQuery来发出JSONP请求的有用之处在于jQuery在后台为你做了 all of the work .

    默认情况下,jQuery要求您在AJAX请求的URL中包含 &callback=? . jQuery将采用您指定的 success 函数,为其指定唯一名称,并将其发布到全局范围 . 然后,它将使用已分配的名称替换 &callback=? 中的问号 ? .


    可比较的JSON / JSONP实现

    以下假定响应对象 { "bar" : "baz" }

    JSON:

    var xhr = new XMLHttpRequest();
    
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
      };
    };
    
    xhr.open("GET", "somewhere.php", true);
    xhr.send();
    

    JSONP:

    function foo(response) {
      document.getElementById("output").innerHTML = response.bar;
    };
    
    var tag = document.createElement("script");
    tag.src = 'somewhere_else.php?callback=foo';
    
    document.getElementsByTagName("head")[0].appendChild(tag);
    
  • 17

    假设你有一些URL给你JSON数据,如:

    {'field': 'value'}
    

    ...你有一个类似的URL,除了它使用JSONP,你传递了回调函数名称'myCallback'(通常通过给它一个名为'callback'的查询参数,例如 http://example.com/dataSource?callback=myCallback ) . 然后它会返回:

    myCallback({'field':'value'})
    

    ...它不仅仅是一个对象,而且实际上是可以执行的代码 . 因此,如果您在页面的其他位置定义一个名为 myFunction 的函数并执行此脚本,则将使用URL中的数据调用该函数 .

    关于这一点很酷的是:您可以创建一个脚本标记并使用您的URL(以 callback 参数完成)作为 src 属性,浏览器将运行它 . 这意味着您可以绕过'same-origin'安全策略(因为浏览器允许您从页面域以外的源运行脚本标记) .

    这是jQuery在发出ajax请求时所做的事情(使用.ajax,'jsonp'作为 dataType 属性的值) . 例如 .

    $.ajax({
      url: 'http://example.com/datasource',
      dataType: 'jsonp',
      success: function(data) {
        // your code to handle data here
      }
    });
    

    在这里,jQuery负责回调函数名称和查询参数 - 使API与其他ajax调用相同 . 但与上面提到的其他类型的ajax请求不同,您不仅限于从与页面相同的来源获取数据 .

  • 1

    JSONP是一种绕过浏览器的方式same-origin policy . 怎么样?像这样:

    enter image description here

    这里的目标是在响应中向 otherdomain.comalert 发出请求 . 通常我们会发出一个AJAX请求:

    $.get('otherdomain.com', function (response) {
      var name = response.name;
      alert(name);
    });
    

    但是,由于请求将发送到其他域,因此无法使用 .

    我们可以使用a来发出请求虽然 <script> 标签 . <script src="otherdomain.com"></script>$.get('otherdomain.com') 都会产生相同的请求:

    GET otherdomain.com
    

    问:但是如果我们使用 <script> 标签,我们如何才能访问响应?如果我们想要 alert ,我们需要访问它 .

    A:呃,我们做不到 . 但这是我们可以做的 - 定义一个使用响应的函数,然后告诉服务器用JavaScript来响应,调用我们的函数并将响应作为其参数 .

    问:但如果服务器不会为我们这样做,并且只愿意将JSON返回给我们呢?

    答:那我们就无法使用它了 . JSONP要求服务器合作 .

    问:必须使用 <script> 标签很难看 .

    答:像jQuery make it nicer这样的库 . 例如:

    $.ajax({
        url: "http://otherdomain.com",
        jsonp: "callback",
        dataType: "jsonp",
        success: function( response ) {
            console.log( response );
        }
    });
    

    它通过动态创建 <script> 标记DOM元素来工作 .

    问: <script> 标签只发出GET请求 - 如果我们想要发出POST请求怎么办?

    答:那么JSONP将不适合我们 .

    问:没关系,我只想提出GET请求 . JSONP太棒了,我打算用它 - 谢谢!

    答:实际上,它真的只是一个黑客 . 而它isn't the safest使用的东西 . 既然CORS可用,您应该尽可能使用它 .

  • 73

    我找到了一篇有用的文章,也很清楚,简单的语言解释了这个主题 . 链接是JSONP

    一些值得注意的要点是:

    • JSONP在CORS之前 .

    • 这是一种从其他域中检索数据的伪标准方法,

    • 它具有有限的CORS功能(仅限GET方法)

    工作如下:

    • <script src="url?callback=function_name"> 包含在html代码中

    • 当执行第1步时,它会感知具有相同函数名称的函数(在url参数中给出)作为响应 .

    • 如果代码中存在具有给定名称的函数,则将执行该数据(如果有)作为该函数的参数返回 .

相关问题