zoukankan      html  css  js  c++  java
  • 同源策略与Jsonp

    同源策略与Jsonp

    同源策略

    同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

    同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
     

    示例:非同源请求报错(项目端口不同)

    项目1:
     
    setting.py 配置静态文件
    STATIC_URL = '/static/'
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'static'),
    )
    

     静态文件: 


    <script src="http://code.jquery.com/jquery-latest.js"></script>

    urls.py
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'index/$',views.index),
        url(r'ajax_send/$',views.ajax_send),
    ]
    

      

     
    views.py
    from django.shortcuts import render,HttpResponse
    
    def index(request):
        return render(request,"index.html")
    
    
    def ajax_send(request):
       print('项目1...............') return HttpResponse("项目1的数据")

      

    index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    <h3>pro1的首页</h3>
    
    <button class="b1">send a request</button>
    </body>
    <script src="/static/jquery.js"></script>
    <script>
        $(".b1").click(function(){
            $.ajax({
                //url:"/ajax_send/", //访问项目1的本路径
                url:"http://127.0.0.1:8080/ajax_send/", //访问项目2的路径,同源策略接收不到数据。
                success:function(data){
                    alert(data);
                }
            })
        })
    
    </script>
    </html>
    

      

    项目2的代码同上

    //===================================setting.py
    
    
    STATIC_URL = '/static/'
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )
    
    
    //===================================urls.py
    
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'index/$',views.index),
        url(r'ajax_send/$',views.ajax_send),
    ]
    
    
    //===================================views.py
    
    from django.shortcuts import render,HttpResponse
    
    def index(request):
        return render(request,"index.html")
    
    
    def ajax_send(request):
       print('项目2..............') return HttpResponse("项目2的数据") //===================================index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h3>pro2的首页</h3> <button class="b2">send a request</button> </body> <script src="/static/jquery.js"></script> <script> $(".b2").click(function(){ $.ajax({ url:"/ajax_send/", success:function(data){ alert(data); } }) }) </script> </html>

      

    同源问题: 当点击项目1的按钮时,发送了请求,但是会发现报错如下:

    已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:7766/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。

    但是注意,项目2中的访问已经发生了,说明是浏览器对非同源请求返回的结果做了拦截。

    注意:jquery.js也是非同源请求,但却能拿到数据。script标签请求不拦截,就拦截ajax请求。

    script标签请求:

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    <h3>pro1的首页</h3>
    
    <button class="b1">send a request</button>
    </body>
    <script src="/static/jquery.js"></script>
    <script>
        /*
        $(".b1").click(function(){
            $.ajax({
                //url:"/ajax_send/", //访问项目1的本路径
                url:"http://127.0.0.1:8080/ajax_send/", //访问项目2的路径
                success:function(data){
                    alert(data);
                }
            })
        })
        */
    </script>
    <!-- 单发一个script请求。刷新页面则请求。-->
    <script src="http://127.0.0.1:8080/ajax_send/"></script>
    
    </html>
    

      

    刷新页面:

     项目2的返回值改成英文。定义成一个变量。

    from django.shortcuts import render,HttpResponse
    
    def index(request):
        return render(request,"index.html")
    
    
    def ajax_send(request):
        print('项目2.........')
        # return HttpResponse("项目2的数据")
        return HttpResponse("baobao")
    

    项目1的js中定义baobao这个变量。运行结果:页面不会报错了。

    <script>
      var baobao="贝贝";
    </script>
    <!-- 单发一个script请求。刷新页面则请求。-->
    <script src="http://127.0.0.1:8080/ajax_send/"></script>
    

      

    运行结果:页面不会报错了。

     定义一个变量是没有意义的。接下来项目1的js中定义一个函数。

    项目1的js中定义一个函数:

    <script>
        // 定义函数
        function baobao(){
            console.log('贝贝');
        }
        // baobao();  //调用函数
    </script>
    <!-- 单发一个script请求。刷新页面则请求。-->
    <script src="http://127.0.0.1:8080/ajax_send/"></script>
    

    项目2返回的值是一个调用函数的字符串。相当于调用了项目1里的函数。

    def ajax_send(request):
        print('项目2.........')
        # return HttpResponse("项目2的数据")
        # return HttpResponse("baobao")
        return HttpResponse("baobao()")
    

     刷新项目1的页面,运行结果如下:

    本质项目1想拿项目2的数据。

    项目2实参上传些值给项目1.

    def ajax_send(request):
        print('项目2.........')
        # return HttpResponse("项目2的数据")
        # return HttpResponse("baobao")
        # return HttpResponse("baobao()")
        return HttpResponse("baobao('项目2的数据')")
    

     项目1接收传参:

    <script>
        function baobao(s){
            console.log(s);
        }
        // baobao('项目2的数据');  //调用函数
    </script>
    <!-- 单发一个script请求。刷新页面则请求。-->
    <script src="http://127.0.0.1:8080/ajax_send/"></script>
    

      

    运行结果:

    假设项目2不发送字符串,而是发送字典类型的数据给项目1。项目1该如何接收???

    项目2:序列化字典:json.dumps(res)

    def ajax_send(request):
        print('项目2.........')
        # return HttpResponse("项目2的数据")
        # return HttpResponse("baobao")
        # return HttpResponse("baobao()")
        # return HttpResponse("baobao('项目2的数据')")
    
        res={"name":"宝宝"}
        import json
        return HttpResponse("baobao('%s')"%json.dumps(res))
    

    项目1:反序列化数据:JSON.parse(s);    JSONP的来历!!!!

    <script>   
        // 接收传参
        // 定义函数
        function baobao(s){
            console.log(s);
            JSON.parse(s);
        }
        // baobao('项目2的数据');  //调用函数
    </script>
    <!-- 单发一个script请求。刷新页面则请求。-->
    <script src="http://127.0.0.1:8080/ajax_send/"></script>
    

      

    项目1刷新页面:运行结果:

     接下来动态定义函数名!!!

     项目1传的的是什么函数名,项目2就是动态的函数名。

     项目1:

    <script>
        // 定义函数
        function foo(s){
            console.log(s);
            JSON.parse(s);
        }
    </script>
    <!-- 项目1传的的是什么函数名,项目2就是动态的函数名。-->
    <script src="http://127.0.0.1:8080/ajax_send/?a=foo"></script>

    项目2:

    
    def ajax_send(request):
        print('项目2.........')
    
        func = request.GET.get("a")
        res={"name":"宝宝"}
        import json
        return HttpResponse("%s('%s')"%(func,json.dumps(res)))
    

      

    运行结果:

     思考:以上都是刷新页面发送请求的,如何点击按钮发送请求呢???

    项目1中新增一个按钮,点击b2发送请求。

     项目1的index.html:

    <button class="b2">send a request_b2</button>
    <script>
        // 思考:以上都是刷新页面发送请求的,如何点击按钮发送请求呢???
        $(".b2").click(function(){
            // 创建一个script标签,添加到body中。
            var $ele_script = $("<script>");
            $ele_script.attr("src","http://127.0.0.1:8080/ajax_send/?a=foo");
            $("body").append($ele_script);
        })
    </script>
    

      

    运行结果:

     项目1:封装功能代码:把路径当成参数动态传值。并且清空该标签。

     项目1:index.html

        // 定义函数
        function foo(s){
            console.log(s);
            JSON.parse(s);
        }
    
        // 封装功能代码:把路径当成参数动态传值。
        function kuayu(url){
            // 创建一个script标签,添加到body中。
            var $ele_script = $("<script>");
            $ele_script.attr("src",url);
            $ele_script.attr("class","kuayu");
            $("body").append($ele_script); //发送请求
            // 请求完成之后删除该标签
            $(".kuayu").remove()
        };
    
        $(".b2").click(function(){
            kuayu("http://127.0.0.1:8080/ajax_send/?a=foo")
        });
    

      

    基于jqeury的API实现跨越请求

     //====================基于jqeury的API实现跨越请求====================

    对script请求的封装

     项目1:

    //====================基于jqeury的API实现跨越请求====================
    $(".b2").click(function(){
        // 跨域请求
        $.getJSON("http://127.0.0.1:8080/ajax_send/?a=?",function(data){
            console.log(data);
        });
    });  

     

    a是一个随机字符串的函数名。

    项目2:

    def ajax_send(request):
        print('项目2.........')
    
        func = request.GET.get("a")
        print("func",func)
        res={"name":"宝宝"}
        import json
        return HttpResponse("%s('%s')"%(func,json.dumps(res)))
    

    项目2运行结果:

    结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个问号是内部自动生成的一个回调函数名。

          此外,如果说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现

     $.ajax

    //====================基于jqeury的API(ajax)实现跨越请求====================

     项目1:

    //====================基于jqeury的API(ajax)实现跨越请求====================
        function baobao(s){
            console.log(s);
        }
    
        $(".b2").click(function(){
            $.ajax({
                url:'http://127.0.0.1:8080/ajax_send/',
                //url:'http://127.0.0.1:8080/ajax_send/?a=baobao',  相当于
                dataType:'jsonp',  // 期待数据类型.会生成script标签请求。
                jsonp: 'a', // 键
                jsonpCallback:"baobao" // 值
            })
    
        });
    

      

    项目1运行结果:

    项目2运行结果:

    //====================以上代码还是要自定义函数,接下来终极版!!!====================

     项目1:

    //====================以上代码还是要自定义函数,接下来终极版!!!====================
    
        $(".b2").click(function(){
            $.ajax({
                url:'http://127.0.0.1:8080/ajax_send/',
                //url:'http://127.0.0.1:8080/ajax_send/?a=随机字符串',
                dataType:'jsonp',  // 期待数据类型.会生成script标签请求。
                jsonp: 'a', //键
                success:function(data){
                    console.log(data);
                }
            })
    
        });
    

      

    项目2的运行结果:

    应用:

    // =========================================================================================
        // 应用
        $(".b2").click(function(){
            $.ajax({
                url:'http://www.jxntv.cn/data/jmd-jxtv2.html?',
                dataType:'jsonp',  // 期待数据类型.会生成script标签请求。
                jsonp: 'callback', //键
                jsonCallback:"list"
            });
    
        });
    
        function list(data){
            //console.log(data.data);
            $.each(data.data,function(i,weekday){
                //console.log(weekday); // {week: "周日", list: Array(19)}
                $("body").append("<p>"+ weekday.week +"</p>");
                //console.log(weekday.list); // {19个数据}  0:{time: "0030", name: "通宵剧场六集连播", link: "http://www.jxntv.cn/live/jxtv2.shtml"}
                $.each(weekday.list,function(j,show){
                    s="<p><a href='+ show.link +'>"+ show.name +"</a><p>"
                    $("body").append(s);
                })
    
            });
        };
    

      

    运行结果:

    总结:

    jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。

    JSONP的原型创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

     将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

    jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法

    <script>
    
        function f(){
    
                $.ajax({
                   url:"http://127.0.0.1:7766/SendAjax/",
                   dataType:"jsonp",            //必须有,告诉server,这次访问要的是一个jsonp的结果。
                   jsonp: 'callbacks',          //jQuery帮助随机生成的:callbacks="wner"
                   success:function(data){
                       alert("hi "+data)
                  }
             });
    
           }
    
    </script>
    

      

      jsonp: 'callbacks'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名'SayHi',server端接受callback键对应值后就可以在其中填充数据打包返回了; 

     jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。利用jQuery可以很方便的实现JSONP来进行跨域访问。  

     注意 JSONP一定是GET请求

  • 相关阅读:
    python随笔:邮箱题目
    05 小程序自定义组件
    04 小程序常用组件-view text rich-text icon swiger
    03 小程序语法-WXSS样式-尺寸-样式 -选择器
    02 小程序语法-数据绑定与事件绑定
    01 小程序入门与vscode开发加装插件
    JAVA25-Git、Vue.js
    JAVA14-File类、递归、字节流、字符流、缓冲流、转换流、序列化流、Files
    JAVA13-异常、线程、同步、等待与唤醒案例、线程池、Lambda表达式
    JAVA12-Scanner类、Random类、ArrayList类、String类、static、Arrays类、Math类、静态方法
  • 原文地址:https://www.cnblogs.com/aaronthon/p/9255892.html
Copyright © 2011-2022 走看看