首页 文章

什么是JSONP?

提问于
浏览
1885

我理解JSON,但不了解JSONP . Wikipedia's document on JSON是(曾)JSONP的热门搜索结果 . 它说:

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

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

2nd search result来自一个名为Remy的人,他写了关于JSONP的文章:

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

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


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


Addendum :我刚刚在维基百科上创建了a new page for JSONP;它现在根据_90605的答案对JSONP进行了清晰而全面的描述 .

8 回答

  • 17

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

    function_prefix(json_object);

    为了使浏览器以 eval "inline"将JSON字符串作为表达式 . 这个技巧使服务器可以直接在客户端浏览器中使用"inject" javascript代码,并绕过"same origin"限制 .

    换句话说,你可以拥有 cross-domain data exchange .


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

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


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

  • 657

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

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

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

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

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

  • 37

    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服务,请访问:this post

  • 10

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

    假设您在域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的一个主要问题:您失去了对请求的大量控制权 . 例如,没有"nice"方法来获取正确的故障代码 . 结果,您最终使用计时器来监视请求等,这总是有点怀疑 . JSONRequest的提议是一个很好的解决方案,允许跨域脚本编写,维护安全性,并允许适当控制请求 .

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

  • 9

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

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

    事情是 - 结果 script 标签可用于a时尚类似于 XMLHttpRequest !看一下这个:

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

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

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

    但是这有点不方便,因为我们必须从 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']});
    

    See where the profit is: 现在我们得到自动回调(my_callback),一旦我们获得数据就会被触发 .
    这就是 JSONP 的全部知识:它是一个回调和脚本标签 .

    NOTE: these are simple examples of JSONP usage, these are not production ready scripts.

    Basic JavaScript example (simple Twitter feed using JSONP)

    <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>
    

    Basic jQuery example (simple Twitter feed using JSONP)

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

  • 1839

    一个使用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;
    
        ?>
    
  • 41

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

    For Further Reading Visit: https://blogs.sap.com/2013/07/15/secret-behind-jsonp/

    client side snippet of code

    <!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>
    

    Server side piece of PHP code

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

    已经给出了很好的答案,我只需要在javascript中以代码块的形式提供我的文章(我还将包括更多现代和更好的跨源请求解决方案:带有HTTP标头的CORS):

    JSONP:

    1.client_jsonp.js

    $.ajax({
        url: "http://api_test_server.proudlygeek.c9.io/?callback=?",
        dataType: "jsonp",
        success: function(data) {
            console.log(data);    
        }
    });​​​​​​​​​​​​​​​​​​
    

    2.server_jsonp.js

    var http = require("http"),
        url  = require("url");
    
    var server = http.createServer(function(req, res) {
    
        var callback = url.parse(req.url, true).query.callback || "myCallback";
        console.log(url.parse(req.url, true).query.callback);
    
        var data = {
            'name': "Gianpiero",
            'last': "Fiorelli",
            'age': 37
        };
    
        data = callback + '(' + JSON.stringify(data) + ');';
    
        res.writeHead(200, {'Content-Type': 'application/json'});
        res.end(data);
    });
    
    server.listen(process.env.PORT, process.env.IP);
    
    console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);
    

    CORS

    3.client_cors.js

    $.ajax({
        url: "http://api_test_server.proudlygeek.c9.io/",
        success: function(data) {
            console.log(data);    
        }
    });​
    

    4.server_cors.js

    var http = require("http"),
        url  = require("url");
    
    var server = http.createServer(function(req, res) {
        console.log(req.headers);
    
        var data = {
            'name': "Gianpiero",
            'last': "Fiorelli",
            'age': 37
        };
    
        res.writeHead(200, {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        });
    
        res.end(JSON.stringify(data));
    });
    
    server.listen(process.env.PORT, process.env.IP);
    
    console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);
    

相关问题