什么是JSONP,为什么创建它?

2022-08-29 21:51:20

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

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

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

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

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

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


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


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


答案 1

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

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

绕过此限制的一个项目是标记。当您使用脚本标记时,域限制将被忽略,但在正常情况下,您无法真正对结果执行任何操作,脚本只是被评估。<script>

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

例如,假设服务器需要一个名为回调的参数来启用其 JSONP 功能。然后,您的请求将如下所示:

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

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

{ foo: 'bar' }

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

mycallback({ foo: 'bar' });

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

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

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

同样值得注意的是JSONP的一个主要问题:你失去了对请求的大量控制。例如,没有“好”的方法来获取正确的故障代码。结果,您最终使用计时器来监视请求等,这总是有点可疑。JSONRequest的主张是一个很好的解决方案,允许跨域脚本,维护安全性,并允许正确控制请求。

如今(2015年),CORS是推荐的方法,而不是JSONRequest。JSONP对于较旧的浏览器支持仍然有用,但考虑到安全隐患,除非您别无选择,否则CORS是更好的选择。


答案 2

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

因此,我们必须使用脚本HTML标签,而不是使用XMLHttpRequest,这些标签通常用于加载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?callback=my_callback';

注意到那边的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 with Padding。(命名非常糟糕的技术,因为它实际上与大多数人认为的“填充”无关。