zoukankan      html  css  js  c++  java
  • JSONP的原理及应用

    JSONP 的原理及应用

    浏览器的同源策略:ajax跨域发送请求,浏览器不接受数据

    但是带有src属性的可以跨域,如script,JSONP就是利用的这种方式

    同源策略参考:

    https://www.zhihu.com/question/25427931/answer/30848852
    https://www.zhihu.com/question/31459669
    https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

    JSONP 技术

    jsonp是一种技术,一种绕过跨域的技巧

    禁止ajax跨域

    下面是使用ajax进行的向百度发送请求,这种情况就是跨域请求,浏览器会禁止接收数据

        <a onclick="sendMsg();">发送</a>
        <script src="/static/jquery-3.2.1.js"></script>
        <script>
            function sendMsg() {
                $.ajax({
                url:'https://www.baidu.com',
                type:'GET',
                success:function (arg) {
                    console.log(arg);//使用ajax(本质是使用的XMLHttprequest) 浏览器的同源策略会禁止接收不同域名的内容
                    /*
                    XMLHttpRequest cannot load https://www.baidu.com/.
                    No 'Access-Control-Allow-Origin' header is present on the requested resource.
                    Origin 'http://127.0.0.1:8000' is therefore not allowed access.
                    */
                }
            })
            }
        </script>
    

    jsonp原理 js代码的执行

    jsonp利用scipt标签的src可以跨域

    在jsonp的head中创建两个js,第一个是js函数,第二个是执行js函数,关键是函数名一致

    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="/static/common.js"></script>
        <script src="/static/common2.js"></script>
    </head>
    

    程序从上往下执行,函数f1,后面执行函数f1并传递参数hello,最终的结果就是页面显示hello

    common

    function f1(arg) {
        alert(arg);
    }
    

    common2

    f1('hello');  // 传递的参数hello
    

    JSONP实现

    通过点击发送标签,js在head创建script标签,script访问http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403,

    返回的数据存放在浏览器的内存中

    返回数据是list(),就是执行list函数。参数是返回值中的内容

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="/static/common.js"></script>
    	//最终就是在这里创建的script标签	
    </head>
    <body>
        <a onclick="sendMsg();">发送</a>
        <script>
            function sendMsg() {
                var tag = document.createElement('script');  //创建标签
                tag.src ="http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403";//这里面的返回的数据是list()  里面的数据是字典的形式
                document.head.appendChild(tag); //找到head标签并添加
            }
        </script>
    </body>
    </html>
    

    common

    //list和返回的名称一致
    function list(arg) {
        console.log(arg);
    }
    

    结果:

    传入的参数是字典类型的,返回的是对象

    jsonp 应用--API

    模拟两个网站,一个是提供数据的网站api,数据是json格式的,设置域名是www.s4.com,端口8001

    另一个www.s5.com,要访问s4的数据

    存放api的网站

    def users(request):
        # v = request.GET.get('callback')
        # print('请求is coming')
        user_list = [
            'aaa',
            'bbb',
            'ccc'
        ]
        return HttpResponse(json.dumps(user_list))
    

    需要在setting中设置允许的host,否则报错

    DisallowedHost at /
    Invalid HTTP_HOST header: 'www.s4.com:8001'. You may need to add 'www.s4.com' to ALLOWED_HOSTS.
    

    访问api的网站

    这个网站定义成www.s5.com:8000 端口8000,访问s4,使用AJAX的XMLHttpresponse访问是不能获取数据的,同源策略会阻止

    def jsonp(request):
        return render(request, 'jsonp.html')
    

    1 使用XMLHttpresponse被拒绝

    在s4的网站已经获取到了请求,但是浏览器同源策略禁止接收返回的数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <input type="button" value="获取用户列表" onclick="getUsers();">
        <ul id="user_list">        
        </ul>
        <script src="/static/jquery-3.2.1.js"></script>
        <script>
            function getUsers() {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function () {
                    if(xhr.readyState == 4){
                        var content = xhr.responseText;
                        console.log(content);
                    }
                };
                xhr.open('GET','http://www.s4.com:8001/users/');
                xhr.send();
            }
        </script>
    </body>
    </html>
    

    2 jsonp解决方案

    被访问的网站s4

    之前返回的数据是[] s5 访问的时候获取到的数据存放在浏览器的内存中,这样就没法获取。最好的方式就是通过变量名获取数据。
    这主要返回的数据是带有名字的。下面在s4端对数据进行拼接。

    def users(request):
        # v = request.GET.get('callback')
        print('请求is coming')
        user_list = [
            'aaa',
            'bbb',
            'ccc'
        ]
        user_list_str = json.dumps(user_list)
        temp = "a=%s" % (user_list_str)   # 对数据进行拼接
        return HttpResponse(temp)
    

    3 增加灵活性

    上面的方式会有变量名重复的问题,而且是全局变量

    下面通过get请求的时候直接发送变零名

    自己的在get请求中定义vername是aaa,这个是任意的。关键是要和API端相互定义好接口

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <input type="button" value="获取用户列表" onclick="getUsers();">
        <script>
           function getUsers () {
                var tag = document.createElement('script');
                tag.src = 'http://www.s4.com:8001/users/?varname=aaa'; //自己定义传输的名字
                document.head.appendChild(tag);
           }
        </script>
    </body>
    </html>
    

    被访问的s4 需要获取get请求中的vername,然后进行拼接。

    def users(request):
        # v = request.GET.get('callback')
        v = request.GET.get('varname')  # 获取get请求中的vername
        print('请求is coming')
        user_list = [
            'aaa',
            'bbb',
            'ccc'
        ]
        user_list_str = json.dumps(user_list)
        temp = "%s=%s" % (v,user_list_str)
        return HttpResponse(temp)
    

    4 服务端返回数据的时间是不确定的

    上面的已经实现了自己定义返回的数据名,但是服务端返回数据的时间是不确定。特别是返回时间特别长的时候,不能立刻获取数据。

    下面在s4服务端进行修改

    关键是temp = "%s(%s)" % (v,user_list_str)

    返回的数据是aaa()的形式,用户获取数据后,有aaa函数,直接执行aaa函数

    def users(request):
        v = request.GET.get('callback')  # 获取callback
        print('请求is coming')
        user_list = [
            'aaa',
            'bbb',
            'ccc'
        ]
        user_list_str = json.dumps(user_list)
        temp = "%s(%s)" % (v,user_list_str)  # 巧妙的方式
        return HttpResponse(temp)
    

    自己的页面

        <script>
           function getUsers () {
                var tag = document.createElement('script');
                tag.src = 'http://www.s4.com:8001/users/?callback=aaa';//aaa是函数名
                document.head.appendChild(tag);
           }
           // 返回数据是aaa()  也就是直接执行下面的函数
           function aaa(arg) {
               console.log(arg)
           }
        </script>
    

    总结:

    客户端

    • URL?callback=xxxx
    • function xxxx(arg){}

    服务端

    • 获取 funcname = request.GET.get(callback)
    • 返回: funcname(....)

    5 使用jQuery的jsonp

    上面的方式是我们自己定义并在页面添加了script,jQuery内部也实现了jsonp

    加上dataType='JSONP'

     <script src="/static/jquery-3.2.1.js"></script>
        <script>
            $.ajax({
                url:'http://www.s4.com:8001/users/?callback=aaa',
                type:'GET',
                dataType:'JSONP',
                success:function (arg) {
                    console.log(arg)
                }
            });
        </script>
    

    6 jsonp 的其他参数

    下面的两个参数会自动的在URL上添加成

    url:'http://www.s4.com:8001/users/?callback=list'

    返回值和函数名是可以修改的,定义成callback和list是一种规范

    jsonp:'callback',
    jsonpCallback:'list',
    
      <script src="/static/jquery-3.2.1.js"></script>
        <script>
          function getUsers() {
                $.ajax({
                url:'http://www.s4.com:8001/users/',
                type:'GET', //只能发送get请求 即便是改成post是发个get请求
                dataType:'JSONP',
                jsonp:'callback',
                jsonpCallback:'list',
                success:function (arg) {
                    console.log(arg)
                }
            });
          }
        </script>
    

    JSONP总结:

    • 是一种约定
    • 自己写动态添加script
    • 使用jQuery的jsonp
    • jsonp只能发送GET请求
    • jsonp解决的是跨域问题
  • 相关阅读:
    【转载】有效防止百度移动搜索转码
    jquery 弥补ie6不支持input:hover状态
    解决 IE6 position:fixed 固定定位问题
    png-24在ie6中的几种透明方法
    Chrome调试小技巧
    html select美化模拟jquery插件select2.js
    响应式设计的十个基本技巧
    colspan和rowspan
    【转】为什么整个互联网行业都缺前端工程师?
    设计模式之桥接模式
  • 原文地址:https://www.cnblogs.com/Python666/p/7138534.html
Copyright © 2011-2022 走看看