jsonp 订阅
JSONP
信息
操作系统
跨平台
开发语言
JavaScript
开源协议
未知
JSONP
浏览器安全模型规定,XMLHttpRequest、框架(frame)等只能在一个域中通信。从安全角度考虑,这个规定很合理;但是,也确实给分布式(面向服务、混搭等等本周提到的概念)Web开发带来了麻烦。 为了实现跨域通信,通常的解决方案有3种: 本地代理: 需要一些硬件设施(没有服务器的客户端无法运行),并且带宽和潜伏时间也要加倍(远程服务器-代理服务器-客户端)。 Flash: 远程主机中需要部署一个crossdomain.xml文件,而且,Flash作为一门专有技术,其前途尚不明朗;换句话说,开发人员很可能要学习一种目标不确定的编程语言。 Script标签: 无法确切知道内容是否有效,没有标准的实现方法,又可能被认为是一种“安全风险”。 在此,我建议使用一种新技术,也是一种独立于标准的方法,即通过script标签来跨域获取数据,名为JSON with Padding,或者就叫 JSONP 。JSONP的原理很简单,但需要服务器端给予相应配合。大致来说,JSONP的实现思路就是在客户端编程时作好使用JSON数据的准备,然后再通过圆括号将这些数据括起来以创建一条有效的JavaScript语句(可能是一次有效的函数调用)。 也就是说,客户端可以使用一个用于命名jsonp的查询参数来决定可以获取的数据。最简单的情况下,如果jsonp参数为空,则返回的数据就是被括在圆括号中的JSON。 下面,我们就以del.icio.us的JSON API为例,来说明JSONP的原理。该API有一个“script tag”变量(即,可以将下面的URL作为script标签的src属性值,用以加载del.icio.us这个API提供的数据。——译者注)如下所示: http://del.icio.us/feeds/json/bob/mochikit+interpreter: if(typeof(Delicious) == 'undefined') Delicious = {}; Delicious.posts = [{ "u": "http://mochikit.com/examples/interpreter/index.html", "d": "Interpreter - JavaScript Interactive Interpreter", "t": [ "mochikit","webdev","tool","tools", "javascript","interactive","interpreter","repl" ] }] 如果用JSONP的方式来表示,那么与此具有相同语义的URL应该是这样的: http://del.icio.us/feeds/json/bob/mochikit+interpreter? jsonp=if(typeof(Delicious)%3D%3D%27undefined%27) Delicious%3D%7B%7D%3BDelicious.posts%3D 单纯看这个URL似乎没有什么,但我们可以要求服务器在数据有效时给出通知。因此,我可以编写一个用于跟踪数据的小系统: var delicious_callbacks = {}; function getDelicious(callback, url) { var uid = (new Date()).getTime(); delicious_callbacks[uid] = function () { delete delicious_callbacks[uid]; callback(); }; url += "?jsonp=" + encodeURIComponent("delicious_callbacks[" + uid + "]"); // 手工输入代码,向文档中插入script标签 }; getDelicious(doSomething, "http://del.icio.us/feeds/json/bob/mochikit+interpreter"); 根据以上假设,用于获取数据的URL应该如下所示: http://del.icio.us/feeds/json/bob/mochikit+interpreter?jsonp=delicious_callbacks%5B12345%5D delicious_callbacks[12345]([{ "u": "http://mochikit.com/examples/interpreter/index.html", "d": "Interpreter - JavaScript Interactive Interpreter", "t": [ "mochikit","webdev","tool","tools", "javascript","interactive","interpreter","repl" ] }]) 可见,由于使用圆括号括住了返回的数据,这就相当于把一个JSONP请求转化成了一次函数调用,或者得到了一个纯粹的JSON直接量。服务器所要配合做的,就是在JSON数据的开头添加一小段文本(即回调函数的名称。——译者注)并将JSON数据放在括号中! 当然,接下来最好是使用Mochikit、Dojo等框架来抽象JSONP,从而让自己省去动手编写DOM以插入script标签的麻烦。 没错,JSONP只是解决了标准化的问题。假如远程主机想通过script标签向页面中注入恶意代码,而不是返回JSON数据,那么页面安全可能会 随时受到威胁。不过,一旦实现了JSONP,那么对开发人员来说肯定是一件省时省力的大好事,在此基础上各种一般化的抽象、教程及文档也会应运而生的。
收起全文
精华内容
下载资源
问答
  • jsonp

    千次阅读 2019-11-27 15:05:36
    jsonp

    1 使用Node.js创建http服务

    ### 查看node版本
    C:\Users\Admin\WebstormProjects\html>node -v
    v12.18.3
    ### 运行js文件
    node xxx.js
    

    2 谷歌游览器设置允许跨域

    --args --disable-web-security  --user-data-dir=F:\chrome


    3 ajax跨域演示

    // 使用node运行当前js文件
    // node http.js
    const http = require('http');
    http.createServer((request, response) => {
        response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
        const weather = "北京 晴 18~32";
        response.write(weather);
        response.end();
    }).listen(8080);
    <!--
        http.html
    -->
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <script>
        $.ajax({
            url: "http://localhost:8080/", success: function (result) {
                alert(result);
            }
        });
    </script>


    4  服务端将要发送的数据填充在一条js语句中

    • 服务端:将要发送的数据填充在一条js语句中
    • 客户端:<script src="服务端接口地址"  
    // node http.js
    const http = require('http');
    http.createServer((request, response) => {
        response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
        const weather = "北京 晴 18~32";
        //将要返回的实际数据,填充进一条合法的js语句中,进而返回一条js语句到客户端被script自动执行
        response.write(`alert("${weather}")`);// alert("北京 晴 18~32")
        response.end();
    }).listen(8080);
    <!--
        http.html
    -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>jsonp-02</title>
    </head>
    <script src="http://localhost:8080/"></script>
    <body>
    </body>
    </html>

     

    // http.js
    const http = require('http');
    http.createServer((request, response) => {
        response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
        const weather = "北京 晴 18~32";
        response.write(`document.write("${weather}")`);// document.write("北京 晴 18~32")
        response.end();
    }).listen(8080);
    <!--
        http.html
    -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>jsonp-03</title>
    </head>
    <script src="http://localhost:8080/"></script>
    <body>
    </body>
    </html>


    5 服务端返回的是一个函数的调用

    提前在客户端定义一个函数,用于处理服务端返回的请求,服务端仅使用函数名拼接一条函数调用的js语句

    5.1  客户端script标签写死了

    const http = require('http');
    const url = require('url');
    
    http.createServer((request, response) => {
        response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
        const Url = url.parse(request.url, true);
        console.log(Url);
        //funName是我请求参数的key
        const funName = Url.query.funName;
        const weather = "北京 晴 18~32";
        response.write(`${funName}("${weather}")`);// funName("北京 晴 18~32") 直接调用这个函数
        response.end();
    }).listen(8080);
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>jsonp-04</title>
    </head>
    
    <script>
        function show(weather) {
            //怎么写由客户端决定
            //document.write(weather);
            //console.log(weather);
            alert(weather);
        }
        //
        //show("来自我自己的天气预报");
    </script>
    <!--!函数定义应该放在上面-->
    <!--script是在页面写死了,只能在加载过程中执行一次-->
    <script src="http://localhost:8080?funName=show">
        
    </script>
    <body>
    </body>
    </html>


    5.2 动态创建script元素

    每次单击按钮时动态创建 <script元素

    const http = require('http');
    const url = require('url');
    
    http.createServer((request, response) => {
        response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
        const Url = url.parse(request.url, true);
        //console.log(Url);
        //funName是我请求参数的key
        const funName = Url.query.funName;
        const weather = "北京 晴 18~32";
        response.write(`${funName}("${weather}")`);// funName("北京 晴 18~32") 直接调用这个函数
        response.end();
    }).listen(8080);
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>jsonp-03</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    </head>
    <button id="click">clickMe</button>
    <script>
        $("#click").click(function () {
            // 不要用$("<script>")动态创建<script>元素
            // 浏览器会强行将<script>解析为标签
            const script = document.createElement("script");
            script.src = 'http://localhost:8080?funName=show';
            document.body.appendChild(script);
        });
        function show(weather) {
            alert(weather);
            //每次单击时都会创建<script>,反复单击会导致<script>堆积
            //删除添加的script元素
            $("body>script:last").remove();
        }
    </script>
    
    <body>
    </body>
    </html>

    6 jQuery 中的jsonp

    jQuery对 jsonp方式跨域进行了终极的简化

    // 服务端的代码还是一样都不能少
    const http = require('http');
    const url = require('url');
    
    http.createServer((request, response) => {
        response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
        const Url = url.parse(request.url, true);
        // 只能是callback
        const callBack = Url.query.callback;
        const weather = "北京 晴 18~32";
        response.write(`${callBack}("${weather}")`);// funName("北京 晴 18~32") 直接调用这个函数
        setTimeout(function () {
            response.end();
        }, 1000);
    }).listen(8080);
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>jsonp-03</title>
    </head>
    
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <button id="click">天气预报</button>
    <script>
        $("#click").click(function () {
            $.ajax({
                url: "http://localhost:8080",
                type: "get",
                // 其实也是动态创建<script>
                // 借助<script>发送跨域请求
                // 必须有服务器端的支持!
                // 打开游览器即可看到
                dataType: "jsonp",
                success: function (weather) {
                    alert(weather);
                }
            });
        });
    </script>
    
    <body>
    </body>
    </html>

     

    // SpringBoot项目
    // http://localhost:5000/getAUth?callback=getAUth
    @ResponseBody
    @GetMapping("/getAUth")
    public String getAUth(@RequestParam String callback) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
    
        HashMap<String, String> auth = new HashMap<String, String>();
        auth.put("1", "添加用户");
        auth.put("2", "添加部门");
        // ...
    
        // 服务端需要特殊处理
        return callback + "(" + mapper.writeValueAsString(auth) + ")";
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>jsonp-05</title>
    </head>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <button id="click">获取权限</button>
    <script>
        let auth;
        $(document).ready(function () {
            $("#click").click(function () {
                $.ajax({
                    url: "http://localhost:5000/getAUth",
                    type: "get",
                    dataType: "jsonp",
                    success: function (data) {
                        auth = data;
                        console.log('auth => ', auth);
                    }
                });
            });
        });
    </script>
    <body>
    </body>
    </html>

     


    7 总结

    jsonp 需要前后端配合

    展开全文
  • JSONP

    2017-10-09 22:21:31
    JSONP

    JSONP是利用浏览器对script的资源引用没有同源限制,通过动态插入一个script标签,当资源加载到页面后会立即执行的原理实现跨域的。JSONP是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback或者开始就定义一个回调方法,参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
    之前有看到一个有形象的解释:Jsonp:json+padding(内填充),把json当做内填充东西,填充到盒子中。

    //JSONP代码,转自switer
    function () {
        var _cbs = {}
        var _ns = '_jsonp'
        var _pn = 'callback'
        var _id = 0
        var _t = 20000
    
        function noop () {}
    
        function jsonp (url, cb, options) {
    
            options = options || {}
            cb = cb || noop
    
            var s = document.createElement('script')
            var cid = _ns + _id ++
            var ended
    
            window[cid] = function (data) {
                onsuccess(data)
                window[cid] = onsuccess = onerror = noop
            }
            function onsuccess (data) {
                document.head.removeChild(s)
                cb(null, data)
            }
            function onerror (e) {
                document.head.removeChild(s)
                cb(e || 'error')
                window[cid] = onsuccess = onerror = noop
            }
            s.onerror = s.onabort = function (e) {
                onerror(e ? e.type : 'error')
            }
            url = url.replace(/[\?\&]$/, '')
            url = url + (~url.indexOf('?') ? '&' : '?') + _pn + '=' + cid
            s.src = url
            document.head.appendChild(s)
            setTimeout(function () {
                onerror('timeout')
            }, options.timeout || _t)
        }
        jsonp.timeout = function (t) {
            _t = t
        }
        jsonp.ns = function (n) {
            _ns = n
        }
        jsonp.pn = function (n) {
            _pn = n
        }
    
        /**
         *  Global namespace is "Routed"
         */
        if (typeof module !== 'undefined' && module.exports) module.exports = jsonp
        else if (typeof exports !== 'undefined') exports.jsonp = jsonp
        else window.jsonp = jsonp
    }();
    展开全文
  • JsonP

    2019-10-11 20:33:46
    什么是 JsonP Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。 为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为...

    什么是 JsonP

    Jsonp(JSON with Padding) json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。

    为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为同源策略

     

    什么是跨域?

    跨域是指一个域(网站)下的文档或脚本试图去请求另一个域(网站)下的资源。

     

    什么是同源策略?

    同源策略/SOPSame origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSSCSFR 等攻击。所谓同源是指"协议++端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。

     

    非同源策略限制以下几种行为:

    1.) CookieLocalStorage IndexDB 无法读取

    2.) DOM Js 对象无法获得

    3.) AJAX 请求不能发送

     

     

    常见跨域场景

     

    跨域解决方案

    1) 通过 jsonp 跨域

    2document.domain + iframe 跨域

    3location.hash + iframe

    4window.name + iframe 跨域

    5postMessage 跨域

    6) 跨域资源共享(CORS

    7nginx 代理跨域

    8nodejs 中间件代理跨域

    9WebSocket 协议跨域

     

    JsonP 优缺点

    JSONP 的优点是:它不像 XMLHttpRequest 对象实现的 Ajax 请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都 可以运行,不需要 XMLHttpRequest ActiveX 的支持;并且在请求完毕后可以通过调用 callback 的方式回传结果。

    JSONP 的缺点则是:它只支持 GET 请求而不支持 POST 等其它类型的 HTTP 请求;它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面之间如何进行 JavaScript 调用的问题。

     

    JsonP 的使用:

    搭建跨域场景

    需求:

    1)创建两个 web 工程,名称为 jsonDemo1(8080)jsonDemo2(9090)

    2jsonDemo1 中提供一个 index.jsp

    3)在 jsonDemo1 index.jsp 中通过 Jquery Ajax 跨域请求 jsonDemo2

    4jsonDemo2 中使用 springMVC 处理请求,返回一个 json 对象

    5)在 jsonDemo1 中将返回的结果插入到 index.jsp

     

    创建项目

    jsonDemo1

     

    jsonDemo2

     

    使用 JsonP 解决跨域:

    Ajax 跨域请求时会出现异常

    ajax 中请求方式有所改变

    <%--
      Created by IntelliJ IDEA.
      User: Administrator
      Date: 2019/10/11
      Time: 9:18
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>首页</title>
        <script type="text/javascript" src="/js/jquery-1.7.2.js"></script>
        <script type="text/javascript">
            $(function () {
    
                $("#but").click(function () {
                    $.ajax({
                        type:"get",
                        url:"http://localhost:9090/user/findUser",
                        dataType:"jsonp",
                        jsonp:"callback",
                        success:function (data) {
                            alert(data);
                            var str="";
                            for (i=0;i<data.length;i++){
                                str+=data[i].userid+" "+data[i].username+" "+data[i].userage;
                            }
                            $("#sp").html(str);
                        }
                    })
    
                })
            })
        </script>
    </head>
    <body>
    <h1>欢迎</h1>
    <span id="sp"></span>
    <input type="button" value="ok" id="but">
    </body>
    </html>
    

     

    请求的 Controller 需要改变(SpringMVC JsonP 的支持

    package com.bjsxt.web.controller;
    
    import com.bjsxt.comments.JsonUtils;
    import com.bjsxt.pojo.Users;
    import org.springframework.http.converter.json.MappingJacksonValue;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Controller
    @RequestMapping("/user")
    public class UserController {
    
        @RequestMapping("/findUser")
        @ResponseBody
        public Object findUser(String callback){
            Users users1=new Users(1,"admin",20);
            Users users2=new Users(2,"zhangsan",20);
            Users users3=new Users(3,"lisi",20);
            List<Users> list= new ArrayList<>();
            list.add(users1);
            list.add(users2);
            list.add(users3);
            //json转换
            MappingJacksonValue mv=new MappingJacksonValue(list);
            mv.setJsonpFunction(callback);
            /*String json=JsonUtils.objectToJson(list);*/
            return mv;
    
    
        }
    }
    

     

     

     

     

     

     

     

    展开全文
  • 说说JSONP

    多人点赞 2019-07-31 19:14:19
    原文地址:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jQuery.html 一、前言: 说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?...

    原文地址:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jQuery.html
    #一、前言:

    说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?这两个问题目前都有不同的解决方案,比如数据可以用自定义字符串、XML、JSON等等来描述,跨域可以通过服务器端代理(如用nginx)、JSONP、添加允许跨域的响应头(即跨域资源共享CORS)这三种方式来解决。其中JSONP就是本文将要讲述的内容。
    JSON和JSONP虽然只有一个字母的差别,但其实他们根本不是一回事儿:JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。我们拿最近比较火的谍战片来打个比方,JSON是地下党们用来书写和交换情报的“暗号”,而JSONP则是把用暗号书写的情报传递给自己同志时使用的接头方式。看到没?一个是描述信息的格式,一个是信息传递双方约定的方法。
    既然随便聊聊,那我们就不再采用教条的方式来讲述,而是把关注重心放在帮助开发人员理解是否应当选择使用以及如何使用上。

    #二、什么是JSON?

    前面简单说了一下,JSON是一种基于文本的数据交换方式,或者叫做数据描述格式,你是否该选用他首先肯定要关注它所拥有的优点。
    JSON的优点:
    1、基于纯文本,跨平台传递极其简单;
    2、Javascript原生支持,后台语言几乎全部支持;
    3、轻量级数据格式,占用字符数量极少,特别适合互联网传递;
    4、可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;
    5、容易编写和解析,当然前提是你要知道数据结构;
    JSON的缺点当然也有,但在作者看来实在是无关紧要的东西,所以不再单独说明。

    JSON的格式或者叫规则:
    JSON能够以非常简单的方式来描述数据结构,XML能做的它都能做,因此在跨平台方面两者完全不分伯仲。
    1、JSON只有两种数据类型描述符,大括号{}和方括号[],其余英文冒号:是映射符,英文逗号,是分隔符,英文双引号"“是定义符。
    2、大括号{}用来描述一组“不同类型的无序键值对集合”(每个键值对可以理解为OOP的属性描述),方括号[]用来描述一组“相同类型的有序数据集合”(可对应OOP的数组)。
    3、上述两种集合中若有多个子项,则通过英文逗号,进行分隔。
    4、键值对以英文冒号:进行分隔,并且建议键名都加上英文双引号”",以便于不同语言的解析。
    5、JSON内部常用数据类型无非就是字符串、数字、布尔、日期、null 这么几个,字符串必须用双引号引起来,其余的都不用,日期类型比较特殊,这里就不展开讲述了,只是建议如果客户端没有按日期排序功能需求的话,那么把日期时间直接作为字符串传递就好,可以省去很多麻烦。

    JSON实例:

    // 描述一个人
    var person = {
        "Name": "Bob",
        "Age": 32,
        "Company": "IBM",
        "Engineer": true
    }
    // 获取这个人的信息
    var personAge = person.Age;
    // 描述几个人
    var members = [
        {
            "Name": "Bob",
            "Age": 32,
            "Company": "IBM",
            "Engineer": true
        },
        {
            "Name": "John",
            "Age": 20,
            "Company": "Oracle",
            "Engineer": false
        },
        {
            "Name": "Henry",
            "Age": 45,
            "Company": "Microsoft",
            "Engineer": false
        }
    ]
    // 读取其中John的公司名称
    var johnsCompany = members[1].Company;
    // 描述一次会议
    var conference = {
        "Conference": "Future Marketing",
        "Date": "2012-6-1",
        "Address": "Beijing",
        "Members": 
        [
            {
                "Name": "Bob",
                "Age": 32,
                "Company": "IBM",
                "Engineer": true
            },
            {
                "Name": "John",
                "Age": 20,
                "Company": "Oracle",
                "Engineer": false
            },
            {
                "Name": "Henry",
                "Age": 45,
                "Company": "Microsoft",
                "Engineer": false
            }
        ]
    }
    // 读取参会者Henry是否工程师
    var henryIsAnEngineer = conference.Members[2].Engineer;
    

    关于JSON,就说这么多,更多细节请在开发过程中查阅资料深入学习。

    #三、什么是JSONP?

    先说说JSONP是怎么产生的:
    其实网上关于JSONP的讲解有很多,但却千篇一律,而且云里雾里,对于很多刚接触的人来讲理解起来有些困难,小可不才,试着用自己的方式来阐释一下这个问题,看看是否有帮助。
    1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;
    2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如script、img、iframe);
    3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;
    4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
    5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
    6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。
    7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
    如果对于callback参数如何使用还有些模糊的话,我们后面会有具体的实例来讲解。

    JSONP的客户端具体实现:
    不管jQuery也好,extjs也罢,又或者是其他支持jsonp的框架,他们幕后所做的工作都是一样的,下面我来循序渐进的说明一下jsonp在客户端的实现:
    1、我们知道,哪怕跨域js文件中的代码(当然指符合web脚本安全策略的),web页面也是可以无条件执行的。
    远程服务器remoteserver.com根目录下有个remote.js文件代码如下:

    alert('我是远程文件');
    

    本地服务器localserver.com下有个jsonp.html页面代码如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
    </head>
    <body>
    
    </body>
    </html>
    

    毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功。

    2、现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。
    jsonp.html页面代码如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript">
        var localHandler = function(data){
            alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result);
        };
        </script>
        <script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
    </head>
    <body>
    
    </body>
    </html>
    

    remote.js文件代码如下:

    localHandler({"result":"我是远程js带来的数据"});
    

    运行之后查看结果,页面成功弹出提示窗口,显示本地函数被跨域的远程js调用成功,并且还接收到了远程js带来的数据。很欣喜,跨域远程获取数据的目的基本实现了,但是又一个问题出现了,我怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。

    3、聪明的开发者很容易想到,只要服务端提供的js脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端“我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。
    看jsonp.html页面的代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript">
        // 得到航班信息查询结果后的回调函数
        var flightHandler = function(data){
            alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
        };
        // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
        var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
        // 创建script标签,设置其属性
        var script = document.createElement('script');
        script.setAttribute('src', url);
        // 把script标签加入head,此时调用开始
        document.getElementsByTagName('head')[0].appendChild(script); 
        </script>
    </head>
    <body>
    
    </body>
    </html>
    

    这次的代码变化比较大,不再直接把远程js文件写死,而是编码实现动态查询,而这也正是jsonp客户端实现的核心部分,本例中的重点也就在于如何完成jsonp调用的全过程。
    我们看到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。
    OK,服务器很聪明,这个叫做flightResult.aspx的页面生成了一段这样的代码提供给jsonp.html(服务端的实现这里就不演示了,与你选用的语言无关,说到底就是拼接字符串):

    flightHandler({
        "code": "CA1998",
        "price": 1780,
        "tickets": 5
    });
    

    我们看到,传递给flightHandler函数的是一个json,它描述了航班的基本信息。运行一下页面,成功弹出提示窗口,jsonp的执行全过程顺利完成!

    4、到这里为止的话,相信你已经能够理解jsonp的客户端实现原理了吧?剩下的就是如何把代码封装一下,以便于与用户界面交互,从而实现多次和重复调用。
    什么?你用的是jQuery,想知道jQuery如何实现jsonp调用?好吧,那我就好人做到底,再给你一段jQuery使用jsonp的代码(我们依然沿用上面那个航班信息查询的例子,假定返回jsonp结果不变):

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     <html xmlns="http://www.w3.org/1999/xhtml" >
     <head>
         <title>Untitled Page</title>
          <script type="text/javascript" src=jquery.min.js"></script>
          <script type="text/javascript">
         jQuery(document).ready(function(){ 
            $.ajax({
                 type: "get",
                 async: false,
                 url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
                 dataType: "jsonp",
                 jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
                 jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
                 success: function(json){
                     alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
                 },
                 error: function(){
                     alert('fail');
                 }
             });
         });
         </script>
         </head>
      <body>
      </body>
     </html>
    

    是不是有点奇怪?为什么我这次没有写flightHandler这个函数呢?而且竟然也运行成功了!哈哈,这就是jQuery的功劳了,jquery在处理jsonp类型的ajax时(还是忍不住吐槽,虽然jquery也把jsonp归入了ajax,但其实它们真的不是一回事儿),自动帮你生成回调函数并把数据取出来供success属性方法来调用,是不是很爽呀?

    ajax与jsonp的异同的补充说明:
    1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;
    2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加script标签来调用服务器提供的js脚本。
    3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。
    4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。
    总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变着一点!
    #四、后端返回JSONP数据
    通过上述描述可以知道,若想实现JSONP,除了前端部分之外,还需要后端的配合,后端需返回符合JSONP要求的数据。
    比如java可以这样写:

    Map<String,String> map = new HashMap<String,String>();   
    map.put("result", "content");  
    String resultJSON = JSONObject.toJSONString(map);
    try {       
    PrintWriter out = response.getWriter();       
    String jsonpCallback = request.getParameter("jsonpCallback");//回调函数
    out.println(jsonpCallback+"("+resultJSON+")");//返回jsonp格式数据 ,要用callback包装下
    out.flush();  
    out.close();  
    } catch (Exception e) {
    e.printStackTrace();
    }
    
    展开全文
  • Jsonp

    2019-05-09 10:22:02
    jsonp是为了解决跨越问题; jsonp的原理: 发送的不是ajax请求;是动态创建了一个script标签(script标签时可以跨域的),把script的src指向了请求时服务的地址;服务地址有个callback函数,在window中注册一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,621
精华内容 8,648
热门标签
关键字:

jsonp