• jsonp


    项目讲完了,但要及时的复习

    今天就来讲一下jsonp,

    先来说一下同源策略。

    同源策略

    一个源的定义:如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的

    一般的http协议会走默认的走80端口,https默认走443端口。域名会翻译成ip地址。

    举个例子:

    下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例:

    URL结果原因
    http://a.xyz.com/dir2/other.html 成功  
    http://a.xyz.com/dir/inner/another.html 成功  
    https://a.xyz.com/secure.html 失败 不同协议 ( https和http )
    http://a.xyz.com:81/dir/etc.html 失败 不同端口 ( 81和80)
         

    同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以xyz.com下的js脚本采用ajax读取abc.com里面的文件数据是会被拒绝的。

    意思就是当我们在访问两个网页时,这两个网页之间的文件数据是不能互相读取的。

    比如说我们在这个页面发送一个Ajax请求去请求另外一

    不受同源策略限制的:

    1. 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。

    2. 跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。

    举个例子

    我们手写两个Django demo:

    demo1:(端口设为8000)

    url.py

    from app01 import views
    
    urlpatterns = [
        url(r'^abc/', views.abc),
    ]

    view.py

    def abc(request):return HttpResponse('alex')

    demo2:(端口设为8005)

    url.py

    from app02 import views
    
    urlpatterns = [
        url(r'^xyz/', views.xyz),
    ]

    views.py

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

    xyz.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <button type="button" id="btn">点我</button>
    <script>
    $('#btn').click(function () {
    $.ajax({
    url:'http://127.0.0.1:8000/',
    type:'get',
    success:function (res) {
    console.log(res)
    }
    })
    })
    </script> {#<script src="http://127.0.0.1:8000/abc/"></script>#} <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> 
    </body>
    </html>

    现在,打开使用浏览器打开http://127.0.0.1:8000/xyz/,点击页面上的 '点我' 按钮,会在console页面发现错误信息如下:

    为什么报错呢?因为同源策略限制跨域发送ajax请求。

    细心点的同学应该会发现我们的demo1项目其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。

    但是我们在页面中的script标签中写入src的cdn方式就可以跨域请求,这就是一个漏洞,我们可以利用这点来搞些事情。我们可以不用在demo2进行点击事件,可以这样

    <script src="http://127.0.0.1:8000/abc"></script>

    这样就会出现这样的报错。

    说是alex没有定义。我们在上面定义一个alex,就不会报错了,var alex = ‘sb’,既然定义一个变量可以,那么定义一个函数名叫alex同样也是可以的,在demo1返回一个alex(),就可以执行demo2中的这个函数。

     //回调函数
    function alex() { console.log(‘我是大帅逼’) }

    这样就可以实现跨域请求了。

    既然可以执行函数,那么当然可以加参数了。在demo1试图函数中添加一个参函数。(因为添加的是一个字典,所以要导入json进行序列化)

    def abc(request):
        res = {'code':0,'data':[0,1,2,3]}
        data_str = json.dumps(res)
        return HttpResponse('alex({})'.format(data_str))

    在demo2中就在函数中加一个参数(也要注意函数要定义在script标签之前,不然会报alex为定义的错误。)

    //回调函数
    function alex(res) { console.log(res) }

    这就实现了在demo2的端口拿到了demo1端口的数据。

     现在是页面刷新就发送请求,那么怎么实现点击之后在发送请求呢?我们有这样一个思路就是在我们点击按钮时,插入一个script标签。

    $('#btn').click(function(){
        var scriptEle = document.createElement('script')    // 创建标签
        $(scriptEle).attr('src','http://127.0.0.1:8000/abc')  //添加属性
        $('body').append(scriptEle)                               //将script标签添加到body
        $(scriptEle).remove()                                      //发送请求后删除
    }
    

     这样同样可以拿到另一个页面的数据,这其实就是jsonp的原理。利用script标签绕过同源策略的限制,拿到数据。

    那么当demo1中有两个试图函数呢?我们怎么实现去访问这两个试图的数据。这当然是写两个点击事件呗。

      function addscriptag(url) {
            var scriptEle = document.createElement('script');
            $(scriptEle).attr('src',url);
            $('body').append(scriptEle);
            $(scriptEle).remove();
        }
        $('#btn').click(function () {
            addscriptag('http://127.0.0.1:8000/abc/')
        });
        $('#btn2').click(function () {
            addscriptag('http://127.0.0.1:8000/cba/')
        });

    这里是将创建script标签写成了函数。这样就能获取到两个视图函数的数据了。

    那我这样写:

    demo2中的script标签:

     function addscriptag(url) {
            var scriptEle = document.createElement('script');
            $(scriptEle).attr('src',url);
            $('body').append(scriptEle);
            $(scriptEle).remove();
        }
        $('#btn').click(function () {
            addscriptag('http://127.0.0.1:8000/abc/?func=alex')
        });
        $('#btn2').click(function () {
            addscriptag('http://127.0.0.1:8000/cba/?func=yangbo')
        });

    这个代码也可以这样写:
    function addscriptag(url,func) {
            var scriptEle = document.createElement('script');
            $(scriptEle).attr('src',url + '?func=' + func);
            $('body').append(scriptEle);
            $(scriptEle).remove();
        }
        $('#btn').click(function () {
            addscriptag('http://127.0.0.1:8000/abc/','alex')
        });
        $('#btn2').click(function () {
            addscriptag('http://127.0.0.1:8000/cba/','yangbo')
        });
     

    demo1中的视图函数:

    def abc(request):
        func = request.GET.get('func')
        res = {'code':0,'data':[0,1,2,3]}
        data_str = json.dumps(res)
        return HttpResponse('{}({})'.format(func,data_str))
    
    def cba(request):
        func = request.GET.get('func')
        res = {'name':'alex','age':20}
        data_str = json.dumps(res)
        return HttpResponse('{}({})'.format(func,data_str))

    当我们点击btn的时候,走的是http://127.0.0.1:8000/abc/?func=alex地址,在demo1的abc视图函数中,get取到func的值,作为参数,并且和数据一起返回,点击btn2的时候同理。

    这样我们就实现了地址的动态变化,只需要你改func后面的内容,就能拿到不同视图函数中的数据。

    但是这样写还是很麻烦。

    jQuery中getJSON方法

    demo2中的js代码:

    $('#btn').click(function () {
            $.getJSON('http://127.0.0.1:8000/abc/?callback=?',function (res) {
                console.log(res)
            })
        })

    demo1的视图函数:

    def abc(request):
        func = request.GET.get('callback')
        res = {'code':0,'data':[0,1,2,3]}
        data_str = json.dumps(res)
        return HttpResponse('{}({})'.format(func,data_str))

    这样是不是就是很简单。格式比较固定都不需用写回调函数。callback后面的那个?是jQuery内部自动生成的一个回调函数名。

    但是如果我们就想实现执行我们自定义的回调函数名,就要用到ajax。

     //回调函数
     function yangbo(res) {
            $.each(res,function (k,v) {
                console.log(k,v)
            })
        }
    
      $('#btn').click(function () {
            $.ajax({
                url:'http://127.0.0.1:8000/abc',
                dataType:'jsonp', //此次请求是jsonp格式
                jsonp:'callback',  //回调函数url的参数名
                jsonpCallback:'yangbo'  // 回调函数
            })
        })

    那能不能再优化一下呢?

      $('#btn').click(function () {
            $.ajax({
                url:'http://127.0.0.1:8000/abc',
                dataType:'jsonp',
                success:function (res) {
                    console.log(res)
                }
            })
        })

    JSONP应用:

    $('#btn').click(function () {
            $.ajax({
                url:'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403',
                dataType:'jsonp',
           jsonp:'callback' jsonpCallback:
    'list', success:function (res) { console.log(res)
             console.log(res.data)
              接下来就进行一些dom操作
    } })

    有几个关键点:回调函数和回调函数url的参数名。

    老师完整代码:

    // 跨域请求示例
    $("#show-tv").click(function () {
      $.ajax({
        url: "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403",
        dataType: 'jsonp',
        jsonp: 'callback',
        jsonpCallback: 'list',
        success: function (data) {
          var weekList = data.data;
          var $tvListEle = $(".tv-list");
          $.each(weekList, function (k, v) {
            var s1 = "<p>" + v.week + "列表</p>";
            $tvListEle.append(s1);
            $.each(v.list, function (k2, v2) {
              var s2 = "<p><a href='" + v2.link + "'>" + v2.name + "</a></p>";
              $tvListEle.append(s2)
            });
            $tvListEle.append("<hr>");
          })
        }
      })
    });
  • 相关阅读:
    Webpack探索【3】--- loader详解
    Webpack探索【2】--- 安装、项目初始化、webpack.config.js配置文件
    Redux
    Object.defineProperty
    Promise A/+ 简单实现
    css 布局
    Redis
    meta 详解
    sublime Text 3 快捷键
    Question
  • 原文地址:https://www.cnblogs.com/yb635238477/p/9520713.html
Copyright © 2020-2023  润新知