• 【Day41】Python之路——AJAX


    什么是AJAX

    AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

    优点:

      不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容

      不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行

    同源策略与jsonp

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

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

    jsonp(jsonpadding)

    之前发ajax的时候都是在自己给自己的当前的项目下发

    现在我们来实现跨域发。

    ajax请求的本质:生成xmlHttpRequest对象
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>index</title>
        <script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script>
    </head>
    <body>
    <form  action="" method="" >
        <input type="text" name="k1" value="v1">
        <input type="text" name="k2" value="v2">
        <input id="forms_btn" type="button" value="提交">
        {% csrf_token %}
    
    </form>
    <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
    
    </body>
    </html>
    前端

    下面是,前端以json格式 发往后端的JavaScript代码

    <script>
       $("#forms_btn").click(function () {
           $.ajax({
               url:"/fromData/",
               type:"post",
               dataType:"json",        // 注意 :是预期服务器返回的数据类型
               headers:{"X-CSRFToken":$("[name='csrfmiddlewaretoken']").val()},
               contentType:"application/json",
               data:{
                   "name":$("[name='k1']").val(),
                   "name":$("[name='k2']").val(),
               },
    
           })
    
        })
    </script>

    注意: 

      1、设置contentType:默认编码格式 “url_encoding” ?a=1&b=2

      2、设置headers

      3、data, 在后端接受到是以二进制形式(b'password=v1&name=v2'),需要反序列化

        前端的JavaScript data{“a”:1,“b”:2}, 其中a,b 可以不用提前定义,就使用,所以可以这样使用:data{a:1,b:2}和Python不同

      4、后台取数据不能在POST中取,需要在body中取

    dataType

    前端设置dataType ,后端如果返回的非json数据,后端不能识别,但是不报错,

    使用Ajax跨域

    view层

    def ajax_send(request):
        func=request.GET.get("callback")
        print("func",func)
        res={"name":"alex"}
        import json
        return HttpResponse("%s('%s')"%(func,json.dumps(res)))

    ajax 无法跨域访问其他网站,

    <script>
    
         $(".b1").click(function () {
             $.ajax({
                 url:"http://127.0.0.1:8002/ajax_send/",    // 浏览器的同源策略的原因,AJax无法发送跨域请求
                 success:function (data) {
                     alert(data)
                 }
             })
         });
    </script>

    下面看如何解决跨域访问

    跨域访问初级版

    <script>
        function foo(s) {
           console.log(s);
           JSON.parse(s)
        }
    
        function kua_yu(url) {
                 // 生成   script标签
                var $ele_script=$("<script>");  注意:使用了 $ele_script创建标签
                $ele_script.attr("src",url);
                $ele_script.attr("class","kuayu");
                // 添加到body中
                $("body").append($ele_script);   // 发送请求
                $(".kuayu").remove()             // 生成之后即删除,不会产生多余的标签
        }
    
        $(".b2").click(function () {
             kua_yu( "http://127.0.0.1:8002/ajax_send/?callback=foo")
        });
    </script>

    跨域访问进阶版

    $(".b1").click(function () {
    
        $.getJSON("http://127.0.0.1:8002/ajax_send/?callback=?",function (data) {   // function 使用了回调函数,
                console.log(data);
            })
    });

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

    跨域访问高级版

    <script>
    $(".b1").click(function () {
    
       $.ajax({
           url:'http://127.0.0.1:8002/ajax_send/',
           dataType:"jsonp",
           jsonp: 'callback',
           jsonpCallback:"SayHi"
       });
    });
    
    $(".b2").click(function () {
    
             $.ajax({
               url:'http://www.jxntv.cn/data/jmd-jxtv2.html?',
               dataType:"jsonp",
               jsonp: 'callback',
               jsonCallback:"list"                            // 访问的函数名,可定制
           });
    
         });
    
    function list(data) {
            console.log(data.data);
            $.each(data.data,function (i,weekday) {
                //console.log(j);  // {week: "周日", list: Array(19)}
                $("body").append("<p>"+weekday.week+"</p>");
                console.log(weekday.list);
                $.each(weekday.list,function (j,show) {
                   s="<p><a href='"+show.link+"'>"+show.name+"</a></p>"
                    $("body").append(s);
    
                })
    
    
            })
    
        }
    
    </script>

    注意:jsonp 一定是GET请求

    csrf跨站请求伪造

    如果把type:"GET"  改为type:"POST" 会报一个Forbidden的错

    解决办法有三种:

    方式一:

         $.ajaxSetup({
                data:{csrfmiddlewaretoken:'{{ csrf_token }}'}
            });
         注意:要放在ajax请求的前面,在发送之前组装一组字符串,在第一步render的时候就发了
         所以有局限性:
            如果把JS代码放到静态文件中,不会渲染,不会执行{{csrf_token}},只能在HTML页面中使用

    方式二:自己组装一组键值对  ( 推荐)

    复制代码
    <form>
    {% csrf_token %}
    </form> data:{ csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), name:$(":text").val(), pwd:$(":password").val() },
    复制代码

    方式三:自己设置头信息

    复制代码
    <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
    $.ajax({ url:"/serialize/", type:"POST", headers:{"X-CSRFToken":$.cookie('csrftoken')}, })
    复制代码

    jQuery.serialize() 

    serialize()函数用于序列化一组表单元素,将表单内容编码为用于提交的字符串

    serialize()函数常用于将表单内容序列化,以便用于AJAX提交。

    该函数主要根据用于提交有效表单控件的name和value,将它们拼接为一个可直接用于表单提交的文本字符串,该字符串已经过标准的URL编码处理(字符集编码为UTF-8)。

    该函数不会序列化不需要提交的表单控件,这和常规的表单提交行为是一致的。例如:不在<form>标签内的表单控件不会被提交、没有name属性的表单控件不会被提交、带有disabled属性的表单控件不会被提交、没有被选中的表单控件不会被提交。

    与常规表单提交不一样的是:常规表单一般会提交带有name的按钮控件,而serialize()函数不会序列化带有name的按钮控件。更多详情请点击这里。

    语法:

    jQueryObject.serialize( )

    serialize()函数的返回值为String类型,返回将表单元素编码后的可用于表单提交的文本字符串。

    请参考下面这段初始HTML代码:

    复制代码
    <form name="myForm" action="http://www.365mini.com" method="post">
        <input name="uid" type="hidden" value="1" />
        <input name="username" type="text" value="张三" />
        <input name="password" type="text" value="123456" />
        <select name="grade" id="grade">
            <option value="1">一年级</option>
            <option value="2">二年级</option>
            <option value="3" selected="selected">三年级</option>
            <option value="4">四年级</option>
            <option value="5">五年级</option>
            <option value="6">六年级</option>
        </select>
        <input name="sex" type="radio" checked="checked" value="1" />男
        <input name="sex" type="radio" value="0" />女
        <input name="hobby" type="checkbox" checked="checked" value="1" />游泳
        <input name="hobby" type="checkbox" checked="checked" value="2" />跑步
        <input name="hobby" type="checkbox" value="3" />羽毛球
        <input name="btn" id="btn" type="button" value="点击" />
    </form>
    复制代码

     对<form>元素进行序列化可以直接序列化其内部的所有表单元素。

    // 序列化<form>内的所有表单元素
    // 序列化后的结果:uid=1&username=%E5%BC%A0%E4%B8%89&password=123456&grade=3&sex=1&hobby=1&hobby=2
    alert( $("form").serialize() );

    我们也可以直接对部分表单元素进行序列化。

    // 序列化所有的text、select、checkbox表单元素
    // 序列化后的结果:username=%E5%BC%A0%E4%B8%89&password=123456&grade=3&hobby=1&hobby=2
    alert( $(":text, select, :checkbox").serialize() );

    示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width">
        <title>Title</title>
    </head>
    <body>
    <form name="myForm" action="http://www.365mini.com" method="post">
        <input name="uid" type="hidden" value="1" />
        <input name="username" type="text" value="张三" />
        <input name="password" type="text" value="123456" />
        <select name="grade" id="grade">
            <option value="1">一年级</option>
            <option value="2">二年级</option>
            <option value="3" selected="selected">三年级</option>
            <option value="4">四年级</option>
            <option value="5">五年级</option>
            <option value="6">六年级</option>
        </select>
        <input name="sex" type="radio" checked="checked" value="1" /><input name="sex" type="radio" value="0" /><input name="hobby" type="checkbox" checked="checked" value="1" />游泳
        <input name="hobby" type="checkbox" checked="checked" value="2" />跑步
        <input name="hobby" type="checkbox" value="3" />羽毛球
        <input name="btn" id="btn" type="button" value="点击" />
    </form>
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
    <script>
        $("#btn").click(function () {
    {#        方式一#}
            //$.ajaxSetup({
              // data:{csrfmiddlewaretoken:'{{ csrf_token }}'}
            //});
            $.ajax({
                url:"/serialize/",
                type:"POST",
    {#            方式三#}
                headers:{"X-CSRFToken":$.cookie('csrftoken')},
                //data:$("form").serialize(),   //序列form表单所有的
                data:$(":text,:password,:checkbox").serialize(),  //序列自己选择的
                success:function (data) {
                    var data=JSON.parse(data);  //js中的反序列化
                    console.log(data);
                    console.log(typeof data);
                    $(".error").html(data);
                }
            })
        })
    </script>
    </body>
    </html>
    
    serialize.html
    serialize.html
    1 def serialize(request):
    2     # form = request.POST
    3     # print(form)
    4     name = request.POST.get("username")
    5     password = request.POST.get("password")
    6     checked = request.POST.getlist("hobby")
    7     print(name,password,checked)
    8     return HttpResponse(json.dumps(name))
    View Code
    当有好多input的时候,就得一一对应的吧所有的数据发过去的,这样显得麻烦,我们用序列化
    jQuery.serialize()
    
    data:$("form").serialize(),   //序列form表单所有的
    data:$(":text,:password,:checkbox").serialize(),  //序列自己选择的
    
    在服务端获取数据
    form = request.POST   
    print(form)   #获取所有
    name = request.POST.get("username")
    password = request.POST.get("password")
    checked = request.POST.getlist("hobby")
    print(name,password,checked)#获取单个

     Ajax上传文件(利用FormData)

    既可以处理二进制,又可以处理字典,列表啊等

    FormData是什么呢?

    XMLHttpRequest Level 2添加了一个新的接口FormData.利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个"表单".比起普通的ajax,使用FormData的最大优点就是我们可以异步上传一个二进制文件.
    所有主流浏览器的较新版本都已经支持这个对象了,比如Chrome 7+、Firefox 4+、IE 10+、Opera 12+、Safari 5+。
    注意:下文中的几个需要解释的
    $("#upload") 拿到的是一个集合
    $("#upload")[0]  就是一个dom对象
    $("#upload")[0].files   拿到的是一个filelist
    $("#upload")[0].files[0]  拿到的是当前最近的文件对象 

    要是使用FormData一定要加上:

    一定要加上:

      contentType:false 
      processDate:false #不做预处理

    ajaxupload.html

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width">
        <title>Title</title>
    </head>
    <body>
    <p>姓名<input type="text" name="username"></p>
    <p>头像<input type="file" id="upload"></p>
    <p><button class="btnnn">提交</button><span class="tishi"></span></p>
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
    <script>
        $(".btnnn").click(function () {
             var formData=new FormData();
            formData.append("username",$(":text").val());
            formData.append("file",$("#upload")[0].files[0]);
            $.ajax({
                url:"/get_upload/",
                type:"POST",
                headers:{"X-CSRFToken":$.cookie('csrftoken')},
                data:formData,
                contentType:false,
                processData:false,
                success:function (data) {
                    $(".tishi").html("上传成功")
                }
    
            })
        })
    </script>
    </body>
    </html>
    复制代码

     view.py

    复制代码
    def ajaxupload(request):
        return render(request,"ajaxupload.html")
    
    def get_upload(request):
        if request.method == "POST":
            print("FIFLE", request.FILES)
            file_obj = request.FILES.get("file")
            print(file_obj.name, "-----")
            file_obj = request.FILES.get("file")
            with open(file_obj.name, "wb") as f:
                for i in file_obj:
                    f.write(i)
            return HttpResponse("上传成功")
  • 相关阅读:
    控件(View)之TextView, Button, ImageButton, ImageView, CheckBox, RadioButton, AnalogClock, DigitalClock【转】
    Android 基础知识
    Intent 的用法
    Layout 和 Menu【转】
    第一讲 深入struts的配置
    第二讲 struts的拦截器
    第三讲 struts验证框架
    vscode Python 无法导入beautifulsoup4解决方案 (bs4报错:vscode unresolved import 'beautifulsoup4')
    BUUCTF RE [GUETCTF2019]re
    Typora破解复现
  • 原文地址:https://www.cnblogs.com/huyangblog/p/8280330.html
Copyright © 2020-2023  润新知