zoukankan      html  css  js  c++  java
  • [oldboy-django][2深入django]浏览器同源策略 + JSONP + cros

    浏览器的同源策略:
        - 同源: 同方法,同域名,同端口
                 http://www.baidu.com:8000
                 http:          方法
                 www.baidu.com: 域名
                 8000:          端口
        - 定义
            网上解析非常好的一篇
            http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
        - 限制 ajax只能发给同源的网址;
               限制原理:
                    浏览器request--->跨域服务器
                    浏览器阻止接收<----跨域服务器响应, 服务器已经做出响应了,而且返回了,只是浏览器阻止接收
    
    
        - 解决策略JSONP
            它的基本思想是,网页通过添加一个<script>元素,请跨域请求放在src属性上
            向服务器请求JSON数据
                (注意数据是json,数据是通过回调函数的参数传递回来的,
                所以参数必须是经过json话
                )
            这种做法不受同源政策限制;
            服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
    
    
        JSONP需求:向其他网站发送http请求
            - 解决办法:浏览器直接发送请求(到访问其他网站)--考虑浏览器同源
                - 要求:
                    1. 客户端
                        - jsonp发送url, 把funname放到url中 url?callback=myfun
                        - 定义myfun函数 function myfun(arg)
    
                    2. 服务端
                        - 获取callback,  fun_name = request.GET.get('callback')
                        - arg是请求,需要获取的数据,这个数据必须字符串或者是Json字符串
                        - 字符串 temp = '%s(%s)' %(fun_name, arg)
                            注意,如果arg是列表等类型要先arg = json.dumps(arg)
                        - 返回字符串
                            return HttpResponse(temp)
    
                    ps: 不是特别必要
                        修改django settings.py里面的ALLOWED_HOSTS = ['http://www.s4.com']
    
                        修改C:WindowsSystem32Driversetchosts里面的内容增加内容
                            127.0.0.1   www.s4.com
                            127.0.0.1   www.s5.com
    
                - 原理:
                    只要页面加载下面语句
                    <script src="http://www.s4.com:8001/user"></script>
                    内存中就会返回http://www.s4.com:8001/user页面内容,
                    并且将内容保存在内存中, 在页面的时候,会将内容当做Js渲染
    
                    当请求http://www.s4.com:8001/user?myfun=callback,
                    后台返回Json.dumps('myfun(arg)'),
                    存储在浏览器内存中,就相当于调用函数 myfun(arg),
                    因此,需要在前端定义callback(arg),这样就不需要考虑什么时候调用函数,
    
                    为了节省空间,一般绑定一个事件动态生成script标签,
                        function xxx(){
                            var tag = document.createElement('script')
                            tag.src = 'http://www.s4.com:8001/user?callback=myfun';
                            document.getElementByTag('head').appendChild(tag);
                        }
    
                        function myfun(arg){
                            console.log(arg);
                        }
    
    
    
    # JSONP实例--动态创建script标签
        # A网站前端
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>Title</title>
            </head>
            <body>
    
            <input type="button" value="jsonp" onclick="test_jsonp();">
    
            <script>
                function test_jsonp(){
                    var tag = document.createElement('script');
                    tag.src = 'http://127.0.0.1:8001/users?callback=get_users';
                    document.head.appendChild(tag);
                }
    
                function get_users(arg){
                    alert(123);
                    console.log(arg)
                }
            </script>
            </body>
            </html>
    
        # B网站处理请求
            url(r'^users', views.users),
            def users(request):
                fun_name = request.GET.get('callback')
                user_list = json.dumps(['alex', 'egon', 'eric'])
                temp = "%s(%s)" % (fun_name, user_list)
                return HttpResponse(temp)
    
    # 用jQuery 封装JSONP,
        # 主要是前端不同,其他的一一致
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <input type="button" value="获取用户列表" onclick="getUsers();">
        </body>
        <script src="/static/js/jquery-1.12.4.js"></script>
        <script>
            function getUsers(){
                $.ajax({
                    url: 'http://127.0.0.1:8001/users',
                    type: 'GET',
                    dataType: 'jsonp',
                    jsonp: 'callback',      // 指定url传递参数名称
                    jsonpCallback: 'myFun' // 指定回调函数
                })
                // jsonp: 'callback', jsonCallback" :'myFun'
                // 等效于将?callback=myFun加到url上
            }
    
            function myFun(arg){
                console.log(arg);
            }
        </script>
        </html>
    
    # jQuery实现跨越的另一种方式$.getJSON()
        利用getJSON来实现,只要在地址中加上callback=?参数即可
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <input type="button" value="获取用户列表" onclick="getUsers();">
        </body>
        <script src="/static/js/jquery-1.12.4.js"></script>
        <script>
            function getUsers(){
                $.getJSON("http://127.0.0.1:8001/users?callback=?", myFun);
            }
    
            function myFun(arg){
                console.log(arg);
            }
    
        </script>
        </html>
    
    
    # 使用jsonp注意:
        - 只能发get请求(生成script标签,里面的src肯定是get请求)
        - 客户端和服务端做好约定
        - jsonp是一项技术,方法;目的是解决跨域问题
    
    
    # 解决跨域请求的另一种方式:cors : cross site
        在响应增加一个响应头:Access-Control-Allow-Origin, 这样就允许ajax跨域发送请求.
        浏览器看到这个消息头,就不会阻止接收跨域返回的响应
        # 视图函数
            obj = HttpResponse()
            obj['Access-Control-Allow-Origin ']= '*'
            # 或者obj['Access-Control-Allow-Origin ']= 'www.s4.com:8000'
            return obj
    
    # cros解决浏览器阻止ajax跨域问题 --简单请求
        - 实例
            # 前端
                <body>
                <input type="button" value="cros支持ajax跨域发送请求" onclick="JsAjaxSend();">
                </body>
                <script src="/static/js/jquery-1.12.4.js"></script>
                <script>
                    function JsAjaxSend() {
                        $.ajax({
                            url: 'http://127.0.0.1:8001/new_users',
                            type: 'GET',
                            success:function(arg){
                             console.log(arg)
                            }
                        })
                    }
                </script>
    
            # http://127.0.0.1:8001/new_users视图函数
                def new_users(request):
                    print('请求来了')
                    user_list = ['alex', 'egon', 'eric']
                    user_list_str = json.dumps(user_list)
                    obj = HttpResponse(user_list_str)
                    obj['Access-Control-Allow-Origin'] = "http://127.0.0.1:8000"
                    return obj
    
    # cros解决ajax跨域请求问题--复杂请求
        复杂请求实际上发送了两个请求: OPTIONS,以及后面的复杂请求。
        # 前端
            function JsAjaxSend() {
    
            $.ajax({
                url: 'http://127.0.0.1:8001/complicated_users',
                type: 'DELETE',
                success:function(arg){
                 console.log(arg)
                }
            })
        }
    
        # 视图 --这里取消了csrf
            def complicated_users(request):
                if request.method == 'OPTIONS':
                    # 设置允许delete方法和浏览器接收跨域响应
                    obj = HttpResponse()
                    obj['Access-Control-Allow-Methods'] = 'DELETE'
                    obj['Access-Control-Allow-Origin'] = "http://127.0.0.1:8000"
                    return obj
                else:
                    user_list_str = json.dumps(['eric', 'alex'])
                    obj = HttpResponse(user_list_str)
                    obj['Access-Control-Allow-Origin'] = "http://127.0.0.1:8000"
                    return obj
    
    
    # 如何区分复杂请求和简单请求
        1、请求方式:HEAD、GET、POST
        2、请求头信息:
            Accept
            Accept-Language
            Content-Language
            Last-Event-ID
            Content-Type 对应的值是以下三个中的任意一个
                                    application/x-www-form-urlencoded
                                    multipart/form-data
                                    text/plain
        注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
    
    # 参考博客
    http://www.cnblogs.com/wupeiqi/articles/5703697.html
    View Code
  • 相关阅读:
    day 46
    day 45 JavaScript 下 函数
    day 42 css 样式
    44 JavaScript
    41 前端
    40 协程 i/0多路复用
    39 线程池 同一进程间的队列
    38 线程 锁 事件 信号量 利用线程实现socket 定时器
    37 生产者消费者模型 管道 进程间的数据共享 进程池
    演示使用string对象
  • 原文地址:https://www.cnblogs.com/liuzhipenglove/p/7896582.html
Copyright © 2011-2022 走看看