zoukankan      html  css  js  c++  java
  • Django

    一、同源策略

    https://www.cnblogs.com/yuanchenqi/articles/7638956.html

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

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

    示例:

    8005:

    from django.contrib import admin
    from django.urls import path
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('index/', views.index),
        path('service/', views.service),
    ]
    
    ---------------------------------------------
    
    from django.shortcuts import render,HttpResponse
    
    def index(request):
        return render(request,'index.html')
    
    def service(request):
        print('端口8005,alex')
        return HttpResponse('端口8005,alex')
    
    -----------------------------------------------
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    
    <h3>index</h3>
    <button class="get_server">alex</button>
    
    
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    
    <script type="text/javascript">
        $('.get_server').click(function () {
            $.ajax({
                url:'/service/',
                success:function (data) {
                    console.log(data)
                }
            })
        })
    </script>
    </body> </html>

    8003:

    urls / view 一致

    注意:url:'http://127.0.0.1:8005/service/  跨域访问,浏览器拦截了!!

    其实/8005/service.... 已经访问了,但是由于 浏览器的同源策略  给拦截了!!

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    
    <h3>index</h3>
    <button class="get_server">egon</button>
    
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    
    <script type="text/javascript">
    
        $('.get_server').click(function () {
    
            $.ajax({
                url:'http://127.0.0.1:8005/service/',
                success:function (data) {
                    console.log(data)
                }
            })
        })
    </script>
    
    </body>
    </html>

    二、Jsonp、cors

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

    那这是,怎么回事呢? 这也是跨域呀!!
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

    2.1、版本1:

    借助script标签,实现跨域请求

     

    8005:

    import json
    def service(request):

    info = {'name':'alex','age':34,'price':200}
    return HttpResponse("func('%s')"%json.dumps(info))

    8003:

    <script type="text/javascript">
    function func(arg) {
    console.log(arg);
    console.log(typeof arg);
    var data = JSON.parse(arg);
    console.log(data);
    console.log(typeof data);
    }

    </script>

    <script src="http://127.0.0.1:8005/service/"></script
    >

    这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

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

    一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。 

    2.2、版本2:

    动态创建script标签

    <button class="get_server">egon</button>

    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

    <script type="text/javascript">
    function func(arg) {
    console.log(arg);
    console.log(typeof arg);
    var data = JSON.parse(arg);
    console.log(data);
    console.log(typeof data);

    }

    function get_jsonp_data(url) {
    var ele_script = $("<script>");
    ele_script.attr("src",url);
    ele_script.attr("id",'jsonp');
    $("body").append(ele_script);
    $("#jsonp").remove();
    }

    $('.get_server').click(function () {
    get_jsonp_data("http://127.0.0.1:8005/service/")
    });

    </script>

    注意:

       function func(arg) {}  必须和 8005的 HttpResponse("func('%s')"%json.dumps(info))  保持一致!

    BUT:

      如何将 主动权 掌握在 客户端 这边?

    $('.get_server').click(function () {
    get_jsonp_data("http://127.0.0.1:8005/service/?callbacks=func")
    });

       

    import json
    def service(request):
    info = {'name':'alex','age':34,'price':200}
    func = request.GET.get('callbacks')
    return HttpResponse("%s('%s')"%(func,json.dumps(info)))

    2.3、版本3:

    Jquery对Jsonp的实现

    <script type="text/javascript">

    function func(arg) {
    console.log(arg);
    console.log(typeof arg);
    var data = JSON.parse(arg);
    console.log(data);
    console.log(typeof data);

    }

    $('.get_server').click(function () {
    // 伪 ajax ,本质上利用 script src 属性
    $.ajax({
    url:'http://127.0.0.1:8005/service/',
    dataType:'jsonp',
    jsonp:'callbacks',
    jsonpCallback:'func'
    });
    });

    </script>

    注意:

    import json
    def service(request):
    info = {'name':'alex','age':34,'price':200}
    func = request.GET.get('callbacks')
    return HttpResponse("%s('%s')"%(func,json.dumps(info)))

    func 不用单独定义一个函数  ?? 其实,jqeury会自动生成随机 str,不用我们管!!

    <button class="get_server">egon</button>

    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

    <script type="text/javascript">

    $('.get_server').click(function () {
    // 伪 ajax ,本质上利用 script src 属性
    $.ajax({
    url:'http://127.0.0.1:8005/service/',
    dataType:'jsonp',
    jsonp:'callbacks',
    success:function (arg) {
    console.log(arg);
    console.log(typeof arg);
    var data = JSON.parse(arg);
    console.log(data);
    console.log(typeof data);
    }
    });
    });

    </script
    >
    import json
    def service(request):
    info = {'name':'alex','age':34,'price':200}
    func = request.GET.get('callbacks') # jQuery21405849947152306905_1529041780670
    return HttpResponse("%s('%s')"%(func,json.dumps(info)))

    2.4、版本4:

    Jsonp应用

     code:

    <h3>index</h3>
    <button class="get_server">egon</button>

    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

    <script type="text/javascript">

    // http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403

    $('.get_server').click(function () {
    // 伪 ajax ,本质上利用 script src 属性
    $.ajax({
    url:'http://www.jxntv.cn/data/jmd-jxtv2.html',
    dataType:'jsonp',
    jsonp:'callbacks',
    jsonpCallback:'list',
    success:function (arg) {
    console.log(arg.data);

    var html = "";
    $.each(arg.data,function (i,weekday) {
    console.log(weekday); // {week: "周日", list: Array(19)}

    html += "<ul>"+weekday.week+"</ul>";

    $.each(weekday.list,function (j,show) {
    html += "<li><a href="+show.link+">"+show.name+"</a>" +
    "&nbsp;&nbsp;<span>"+show.time+"</span></li>";

    })
    });

    $('body').append(html);
    }
    });
    });

    </script>

    2.5、版本5:

    cors

    get请求,注意

    response['Access-Control-Allow-Origin'] = "http://127.0.0.1:8003"

    <script type="text/javascript">

    $('.get_server').click(function () {
    $.ajax({
    url:'http://127.0.0.1:8005/service/',
    success:function (arg) {
    console.log(arg);
    console.log(typeof arg);
    var data = JSON.parse(arg);
    console.log(data);
    console.log(typeof data);
    }

    })
    })

    </script>
    import json
    def service(request):
    info = {'name':'alex','age':34,'price':200}

    response = HttpResponse(json.dumps(info))

    # 告诉浏览器 你别拦了
    # response['Access-Control-Allow-Origin'] = "http://127.0.0.1:8003"
    response['Access-Control-Allow-Origin'] = "*"

    return response

    三、补充cors - 简单请求,复杂请求

    一、简介

    CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

    二、两种请求

    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

    只要同时满足以下两大条件,就属于简单请求。

    复制代码
    (1) 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
    (2)HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
    复制代码

    凡是不同时满足上面两个条件,就属于非简单请求。

    浏览器对这两种请求的处理,是不一样的。

    复制代码
    * 简单请求和非简单请求的区别?
    
       简单请求:一次请求
       非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
    * 关于“预检”
    
    - 请求方式:OPTIONS
    - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
    - 如何“预检”
         => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
            Access-Control-Request-Method
         => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
            Access-Control-Request-Headers
    复制代码

    支持跨域,简单请求

    服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

    支持跨域,复杂请求

    由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。

    • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
    • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers

    https://www.cnblogs.com/yuanchenqi/articles/7638956.html#_label7

    http://www.cnblogs.com/wupeiqi/articles/5703697.html

        简单请求 复杂请求
                条件:
                
                    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
                 
                    注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
                    
                    如果是复杂请求: 
                        options请求进行预检,通过之后才能发送POST请求
                    
                

    遇到跨域,简单请求 复杂请求

    写一个中间件:

    cors.py:

    from django.utils.deprecation import MiddlewareMixin
    
    class CORSMiddleware(MiddlewareMixin):
        def process_response(self,request,response):
            # 允许你的域名来访问
            response['Access-Control-Allow-Origin'] = "*"
    
            if request.method == 'OPTIONS':
                # 允许你携带 Content-Type 请求头 不能写*
                response['Access-Control-Allow-Headers'] = 'Content-Type'
                # 允许你发送 DELETE PUT请求
                response['Access-Control-Allow-Methods'] = 'DELETE,PUT'
    
            return response



    Django处理PUT请求有几个点需要注意:

    CSRF配置

    为了防止跨站攻击,Django默认会对POST/PUT/DELETE这几种操作进行csrf token检查。POST可以将其放到post的参数中,但Django对PUT/DELETE只能通过检查Header的方式检查csrf token。
    所以应当在HTML中确认发送之前配置了Ajax的头:

        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
    
    
            $.ajaxSetup({
                beforeSend: function(xhr, settings) {
                    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                        xhr.setRequestHeader("X-CSRFToken", csrftoken);
                    }
                }
            });
    

    通过Ajax发送PUT/DELETE请求

    需要注意的几个地方:

    1. 设置type为PUT,DELETE同理

    2. url必须以/结尾

           $.ajax({
               url: dbUrl + tableName + "/",   // Append back slash for put request
               type: "PUT",
               data: {"key": key, "field": field, "field-value": input.value},
               success: function(result) {
                   input.style.backgroundColor = "#b3ffb3";
               },
               error: function(event, XMLHttpRequest, ajaxOptions, thrownError) {
                   input.style.backgroundColor = "#ffad99";
                   input.value = oldValue
               }
           });
      

    后台处理参数

    Django对于PUT/DELETE请求并没有像POST/GET那样有一个字典结构。我们需要手动处理request.body获取参数:

        from django.http import QueryDict
    
        put = QueryDict(request.body)
        key = put.get('key')
        field = put.get('field')
        field_value = put.get('field-value')

    发的delete请求:


    $.ajax({
      url: "/administration/detail/",
      type: "delete",
      headers: {"X-CSRFtoken": $('input[name="csrfmiddlewaretoken"]').val()},
      data: {
        user_name: user,
        app_list: JSON.stringify(permissions_list),
      },
      success: function (res) {

      }
    })

     

  • 相关阅读:
    OpenStack对象存储管理手册(5) OpenStack对象存储系统管理3
    hdu1568Fibonacci
    智能手机中显示信号强度格数
    上篇日本人经营之道 一破坏对手的情绪乱其方寸
    基于Wince的计算器程序
    shell 字符串操作
    轻松记住大端小端的含义
    如何把手机变成你的救生设备
    PM是一个事实
    mysql 5.6 online ddl 测试
  • 原文地址:https://www.cnblogs.com/alice-bj/p/9185998.html
Copyright © 2011-2022 走看看