协慌网

登录 贡献 社区

什么是 JSONP?

我理解 JSON,但不了解 JSONP。 维基百科关于 JSON 的文档是 JSONP 的最佳搜索结果。它说:

JSONP 或 “带填充的 JSON” 是 JSON 扩展,其中前缀被指定为调用本身的输入参数。

咦?什么电话?这对我没有任何意义。 JSON 是一种数据格式。没有电话。

第二个搜索结果来自一个名叫Remy 的人 ,他写了一篇关于 JSONP 的文章:

JSONP 是脚本标记注入,将响应从服务器传递到用户指定的函数。

我可以理解这一点,但它仍然没有任何意义。


那么什么是 JSONP?它为什么被创建(它解决了什么问题)?我为什么要用呢?


附录 :我刚刚在维基百科上为 JSONP创建了一个新页面 ; 根据jvenema的回答,它现在对 JSONP 进行了清晰而全面的描述。

答案

它实际上并不太复杂......

假设您在域 example.com 上,并且您想向域 example.net 发出请求。要做到这一点,你需要跨越域边界,在大多数浏览器领域都是禁忌。

绕过此限制的一项是 执行任何操作,只会对脚本进行评估。

输入 JSONP。当您向启用了 JSONP 的服务器发出请求时,您会传递一个特殊参数,告诉服务器一些关于您的页面的信息。这样,服务器就能够以您的页面可以处理的方式很好地包装其响应。

例如,假设服务器需要一个名为 “callback” 的参数来启用其 JSONP 功能。然后你的请求看起来像:

http://www.example.net/sample.aspx?callback=mycallback

如果没有 JSONP,这可能会返回一些基本的 JavaScript 对象,如下所示:

{ foo: 'bar' }

但是,使用 JSONP 时,当服务器收到 “callback” 参数时,它会以不同的方式包装结果,返回如下内容:

mycallback({ foo: 'bar' });

如您所见,它现在将调用您指定的方法。因此,在您的页面中,您定义了回调函数:

mycallback = function(data){
  alert(data.foo);
};

现在,当加载脚本时,它将被评估,并且您的函数将被执行。 Voila,跨域请求!

值得注意的是 JSONP 的一个主要问题:您失去了对请求的大量控制权。例如,没有 “好的” 方法来获取正确的故障代码。结果,您最终使用计时器来监视请求等,这总是有点怀疑。 JSONRequest的提议是允许跨域脚本编写,维护安全性以及允许对请求进行适当控制的绝佳解决方案。

这些天(2015 年), CORS是推荐的方法与 JSONRequest。 JSONP 对于较旧的浏览器支持仍然有用,但鉴于安全隐患,除非您没有选择,否则 CORS 是更好的选择。

JSONP实际上是一个克服XMLHttpRequest相同域策略的简单技巧。 (如您所知,无法将AJAX(XMLHttpRequest)请求发送到其他域。)

所以 - 我们不得不使用XMLHttpRequest,而是使用脚本 HTML 标签,这些标签通常用于加载 js 文件,以便 js 从另一个域获取数据。听起来怪怪的?

事情是 - 结果脚本标签可以以类似于XMLHttpRequest的方式使用!看一下这个:

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data';

在加载数据后,您将得到一个如下所示的脚本段:

<script>
{['some string 1', 'some data', 'whatever data']}
</script>

但是这有点不方便,因为我们必须从脚本标记中获取此数组。所以JSONP 的创建者认为这会更好(并且是):

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data <b>?callback=my_callback</b> ';

注意那边的 my_callback函数?所以 - 当JSONP服务器收到你的请求并找到回调参数 - 而不是返回普通的 js 数组时,它将返回:

my_callback({['some string 1', 'some data', 'whatever data']});

看看利润在哪里:现在我们得到自动回调(my_callback),一旦我们获得数据就会被触发。
这就是JSONP的全部知识:它是一个回调和脚本标签。

注意:这些是 JSONP 使用的简单示例,这些不是生产就绪脚本。

基本 JavaScript 示例(使用 JSONP 的简单 Twitter 提要)

<html>
    <head>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
        <script>
        function myCallback(dataWeGotViaJsonp){
            var text = '';
            var len = dataWeGotViaJsonp.length;
            for(var i=0;i<len;i++){
                twitterEntry = dataWeGotViaJsonp[i];
                text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
            }
            document.getElementById('twitterFeed').innerHTML = text;
        }
        </script>
        <script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>
    </body>
</html>

基本的 jQuery 示例(使用 JSONP 的简单 Twitter 提要)

<html>
    <head>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                $.ajax({
                    url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10',
                    dataType: 'jsonp',
                    success: function(dataWeGotViaJsonp){
                        var text = '';
                        var len = dataWeGotViaJsonp.length;
                        for(var i=0;i<len;i++){
                            twitterEntry = dataWeGotViaJsonp[i];
                            text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
                        }
                        $('#twitterFeed').html(text);
                    }
                });
            })
        </script>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
    </body>
</html>


JSONP代表带有填充的 JSON 。 (技术名称很差,因为它与大多数人认为的 “填充” 无关。)

JSONP 通过构造 “脚本” 元素(在 HTML 标记中或通过 JavaScript 插入 DOM)来工作,该元素请求远程数据服务位置。响应是一个 javascript 加载到您的浏览器上,其中包含预定义函数的名称以及传递的参数,即请求的 JSON 数据。当脚本执行时,该函数与 JSON 数据一起被调用,允许请求页面接收和处理数据。

如需进一步阅读,请访问: https //blogs.sap.com/2013/07/15/secret-behind-jsonp/

客户端代码片段

<!DOCTYPE html>
    <html lang="en">
    <head>
     <title>AvLabz - CORS : The Secrets Behind JSONP </title>
     <meta charset="UTF-8" />
    </head>
    <body>
      <input type="text" id="username" placeholder="Enter Your Name"/>
      <button type="submit" onclick="sendRequest()"> Send Request to Server </button>
    <script>
    "use strict";
    //Construct the script tag at Runtime
    function requestServerCall(url) {
      var head = document.head;
      var script = document.createElement("script");

      script.setAttribute("src", url);
      head.appendChild(script);
      head.removeChild(script);
    }

    //Predefined callback function    
    function jsonpCallback(data) {
      alert(data.message); // Response data from the server
    }

    //Reference to the input field
    var username = document.getElementById("username");

    //Send Request to Server
    function sendRequest() {
      // Edit with your Web Service URL
      requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");
    }    

  </script>
   </body>
   </html>

服务器端的 PHP 代码

<?php
    header("Content-Type: application/javascript");
    $callback = $_GET["callback"];
    $message = $_GET["message"]." you got a response from server yipeee!!!";
    $jsonResponse = "{\"message\":\"" . $message . "\"}";
    echo $callback . "(" . $jsonResponse . ")";
?>