题 什么是JSONP?


我理解JSON,但不了解JSONP。 维基百科关于JSON的文档 是(曾)是JSONP的热门搜索结果。它说:

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

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

第二个搜索结果 来自一些名叫的人 雷米谁写了关于JSONP的文章:

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

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


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


附录:我刚刚创建了 JSONP的新页面 在维基百科上;它现在有一个清晰而全面的JSONP描述,基于 jvenema的答案。


1835
2018-01-14 20:53


起源


Skaffman,我是否从你那种从WIKIpedia中删除完全合理问题的人那里听到了这种语气?没有添加任何东西或改进它?如何提出问题是“故意破坏”。啧。是的,就在这个时刻,我将使用jvenema提供的信息改进维基百科页面。 - Cheeso
太好了,如果你有更好的信息,那就添加它。但你不在维基百科上提问,你添加事实。 - skaffman
对于记录,如果您不信任与100%通话的服务器,请不要使用JSONP。如果它被泄露,您的网页将受到轻微损害。 - ninjagecko
另请注意JSONP 可以被劫持 如果没有正确实施。 - Pacerier
当问题是10个月的“重复”时,为什么这个问题被标记为重复 后 这个? - jvenema


答案:


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

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

绕过此限制的一项是<script>标记。当您使用脚本标记时,域限制将被忽略,但在正常情况下,您不能真正  任何结果,脚本只是得到评估。

输入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是更好的选择。


1796
2018-01-14 21:08



请注意,使用JSONP会带来一些安全隐患。由于JSONP实际上是javascript,它可以执行javascript可以执行的所有操作,因此您需要信任JSONP数据的提供程序。我在这里写了关于它的som博客文章: erlend.oftedal.no/blog/?blogid=97 - Erlend
JSONP中是否存在<script>标记中没有的新安全隐含?使用脚本标记,浏览器隐式信任服务器以提供无害的Javascript,浏览器会盲目地评估。 JSONP会改变这个事实吗?它似乎没有。 - Cheeso
不,它没有。你信任它提供javascript,同样的事情适用于JSONP。 - jvenema
值得注意的是,您可以通过更改数据的返回方式来提高安全性。如果以真正的JSON格式返回脚本,例如mycallback('{“foo”:“bar”}')(注意参数现在是一个字符串),那么您可以自己手动解析数据以“清理”它之前评估。 - jvenema
CURL是服务器端解决方案,而不是客户端。它们有两个不同的用途。 - jvenema


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?回调= 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。 (技术名称很差,因为它与大多数人认为的“填充”无关。)


640
2017-07-29 21:40



感谢脚本标记说明。我无法弄清楚JSONP是如何绕过跨域安全策略的。在解释之后,我觉得有点愚蠢错过这一点...... - Eduard
对于jvenema的答案,这是一个非常好的补充答案 - 我不明白为什么回调是必要的,直到你指出json数据否则必须通过script元素访问。 - Matt
知道脚本标签工作为XMLHttp后感觉很棒:-)感谢您的好解释 - ravisoni
谢谢你这么清楚的解释。我希望我的大学教科书是由像你这样的人写的:) - hashbrown
很好的解释而不是前一个。 Ofcourse-你的摘录“你通常用来加载js文件的那些,以便js从另一个域获取数据。听起来很奇怪?”对我来说也是一个大开眼界。示例代码非常杰出。 - SIslam


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 . ")";
?>

38
2018-03-17 13:32



现在顶部的链接只有404s - Man Personson
该链接的内容现在可在 http://scn.sap.com/community/developer-center/front-end/blog/2013/07/15/secret-behind-jsonp。 - ᴠɪɴᴄᴇɴᴛ


因为您可以要求服务器将前缀附加到返回的JSON对象。例如

function_prefix(json_object);

为了浏览器 eval 将JSON字符串“内联”为表达式。这个技巧使服务器可以直接在客户端浏览器中“注入”javascript代码,并绕过“相同的来源”限制。

换句话说,你可以拥有 跨域数据交换


一般, XMLHttpRequest 不允许直接跨域数据交换(一个需要通过同一域中的服务器),而:

<script src="some_other_domain/some_data.js&prefix=function_prefix>`可以从不同于原点的域访问数据。


另外值得注意的是:即使在尝试那种“技巧”之前服务器应被视为“可信”,也可以包含对象格式等可能变化的副作用。如果一个 function_prefix(即,正确的js函数)用于接收JSON对象,所述函数可以在接受/进一步处理返回的数据之前执行检查。


37
2018-01-14 20:58





JSONP是一个很好的解决跨域脚本错误。您可以完全使用JS来使用JSONP服务,而无需在服务器端实现AJAX代理。

你可以使用 b1t.co 服务,看看它是如何工作的。这是一个免费的JSONP服务,可以帮助您缩小URL。以下是用于服务的URL:

http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]

比如电话, http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com

会回来的

whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});

因此当这个get作为src加载到你的js中时,它会自动运行你应该实现的任何JavascriptName作为你的回调函数:

function minifyResultsCallBack(data)
{
    document.getElementById("results").innerHTML = JSON.stringify(data);
}

要实际进行JSONP调用,可以通过多种方式(包括使用jQuery)来实现,但这里是一个纯JS示例:

function minify(urlToMinify)
{
   url = escape(urlToMinify);
   var s = document.createElement('script');
   s.id = 'dynScript';
   s.type='text/javascript';
   s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
   document.getElementsByTagName('head')[0].appendChild(s);
}

可以在以下位置获得分步示例和jsonp Web服务以进行练习: 这个帖子


17
2018-03-28 15:59



谢谢你发布你的答案!请注意,您应该在此网站上发布答案的基本部分,或者删除您的帖子风险 请参阅常见问题解答,其中提到了“仅仅是一个链接”的答案。 如果您愿意,您仍可以包含该链接,但仅作为“参考”。答案应该独立而不需要链接。 - Taryn♦


一个使用JSONP的简单示例。

client.html

    <html>
    <head>
   </head>
     body>


    <input type="button" id="001" onclick=gO("getCompany") value="Company"  />
    <input type="button" id="002" onclick=gO("getPosition") value="Position"/>
    <h3>
    <div id="101">

    </div>
    </h3>

    <script type="text/javascript">

    var elem=document.getElementById("101");

    function gO(callback){

    script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://localhost/test/server.php?callback='+callback;
    elem.appendChild(script);
    elem.removeChild(script);


    }

    function getCompany(data){

    var message="The company you work for is "+data.company +"<img src='"+data.image+"'/   >";
    elem.innerHTML=message;
}

    function getPosition(data){
    var message="The position you are offered is "+data.position;
    elem.innerHTML=message;
    }
    </script>
    </body>
    </html>

server.php

  <?php

    $callback=$_GET["callback"];
    echo $callback;

    if($callback=='getCompany')
    $response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";

    else
    $response="({\"position\":\"Development Intern\"})";
    echo $response;

    ?>    

10
2018-06-06 06:45





在了解JSONP之前,您需要了解JSON格式和XML。目前,Web上最常用的数据格式是XML,但XML非常复杂。它使用户不方便处理嵌入在网页中的内容。

为了使JavaScript能够轻松交换数据,即使作为数据处理程序,我们也会根据JavaScript对象使用措辞并开发出简单的数据交换格式,即JSON。 JSON可以用作数据,也可以用作JavaScript程序。

JSON可以直接嵌入到JavaScript中,使用它们可以直接执行某些JSON程序,但由于安全限制,浏览器Sandbox机制会禁用跨域JSON代码执行。

为了使JSON可以在执行后传递,我们开发了一个JSONP。 JSONP通过JavaScript回调功能和<script>标记绕过了浏览器的安全限制。

简而言之,它解释了JSONP是什么,它解决了什么问题(何时使用它)。


9
2017-12-08 04:02



我赞同这一点,因为我不相信在2015年12月,XML是网络上最常用的数据格式。 - RobbyD