zoukankan      html  css  js  c++  java
  • ajax

    8. ajax
    ![img](file:///C:UsersLenovoAppDataRoamingTencentQQTempSys%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9524153.html

    1、ajax简单介绍

    我们以前知道的前端向后端发送数据的方式有:
      GET:地址栏、a标签、Form表单
      POST:Form表单
    
    那么现在我们在学习一种:那就是ajax
    ajax:也是前端向后端发送数据的一种方式
    
    AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
    
    同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
    异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
    Ajax的特点:
      异步交互: 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
      局部刷新:  整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
    

    form表单提交就刷新,而ajax则保留数据,并进行局部刷新

    form表单

    post时由name属性携带数据

    html文件

        <form action="" method="post">
            用户名:<input type="text" name="username">
            密码:<input type="password" name="password" >
            <input type="submit">
        </form>
    

    views文件

    def login(request):
        if request.method == "GET":
            return render(request,"login.html")
        else:
            user = request.POST.get("username")
            pwd = request.POST.get("password")
            if user == "alex" and pwd == "123":
                return HttpResponse("ok")
            else:
                return redirect("login")
    

    ajax 表单

    post时不用name携带数据,自己data自己获取数据提交

    get请求

    login.html文件

    <body>
        用户名:<input type="text" id="username">
        密码:<input type="password" id="password">
        <button id="sub">提交</button>
    
        <script src="{% static 'jquery.js' %}"></script>
        <script>
    {# 绑定点击事件       #}
            $("#sub").click(function(){
                var uname = $("#username").val();
                var pwd = $("#password").val();
                {#固定写法如下#}
                $.ajax({
                    url:"{% url 'login' %}",   {# 等同于 url:"/login/"  #}
                    type:"get",
                    success:function (res) {
                        console.log(res);
                    }
                })
            })
        </script>
    </body>
    

    views文件不变,验证匿名函数res内容,get请求情况下,提交订单,在页面console下查看内容,

    结论:res就是login函数的返回值,本题中返回的是login.html文件

    post请求

    views页面

    from django.shortcuts import render,HttpResponse,redirect
    
    def login(request):
        if request.method == "GET":
            return render(request,"login.html")
        else:
            user = request.POST.get("username")
            pwd = request.POST.get("password")
            if user == "alex" and pwd == "123":
                return HttpResponse("1")
            else:
                # return redirect("login")
                return HttpResponse("0")
    
    def home(request):
        return render(request,"home.html")
    

    home.html 文件

    <h1>欢迎光临24期教室</h1>
    

    login.html文件

    {% load static %}   {# 固定写法,不可修改 #}
    <!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, initial-scale=1">
        <title>Bootstrap 101 Template</title>
    
    </head>
    <body>
        用户名:<input type="text" id="username">
        密码:<input type="password" id="password">
        <button id="sub">提交</button>
        <span class="error"></span>
    
        <script src="{% static 'jquery.js' %}"></script>
        <script>
    {# 绑定点击事件       #}
            $("#sub").click(function(){
                var uname = $("#username").val();
                var pwd = $("#password").val();
                {#固定写法如下#}
                $.ajax({
                    url:"{% url 'login' %}",   {# 等同于 url:"/login/"  #}
                    type:"post",
                    data:{username:uname,password:pwd},
                    success:function (res) {
                        {#console.log(res);#}
                        if (res === "1"){
                            {#$(".error").text("登陆成功")#}
                            location.href = "/home/";  {# 页面跳转 #}
                        }else{
                            $(".error").text("用户名或密码错误")
                        }
                    }
                })
            })
        </script>
    </body>
    </html>
    

    此过程如下,首先浏览器输入http://127.0.0.1/login/ 请求数据 (get) -- 视图函数执行 --- 返回渲染后的login.html页面给浏览器 --- 浏览器得到页面提交,触发post请求 ,及点击事件 --- 执行return给res,并执行click事件,已成功为例,返回给浏览器http://127.0.0.1/home/路径 -- 浏览器得到路径在请求home函数,---后端得到请求返回home.html给浏览器

    2. csrf_token

    页面安全认证机制,跨站请求伪造,没此机制,Forbidden (403)

      所以解决csrf攻击的最直接的办法就是生成一个随机的csrftoken值,保存在用户的页面上,每次请求都带着这个值过来完成校验。

    源码解释:
    token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。
    django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法。
    同样也不难解释,为什么ajax请求时,需要从cookie中拿取token添加到请求头中。
    

    settings中的'django.middleware.csrf.CsrfViewMiddleware', ,get不报错,post报错

    form表单请求认证

    login.html文件

    {% csrf_token %}必须在form表单内部,代码生成一个键值对数据,form表单name属性携带提交的数据

        <form action="" method="post">
        	{% csrf_token %}
            用户名:<input type="text" name="username">
            密码:<input type="password" name="password" >
            <input type="submit">
        </form>
        
        {% csrf_token %}请求后自动生成一个验证记录,post时后台会根据cookie解码相同则验证成功
        <input type='hidden' name='csrfmiddlewaretoken' value='xxmPzC6BcpPWLt5usmFsYB858UM5SczoHyEHt8yad77XdYsj3TM3qC2WHPPyXa5G' />
    

    views文件

    def login(request):
        if request.method == "GET":
            return render(request,"login.html")
        else:
            user = request.POST.get("username")
            pwd = request.POST.get("password")
            if user == "alex" and pwd == "123":
                return HttpResponse("1")
            else:
                # return redirect("login")
                return HttpResponse("0")
    

    ajax 请求认证

    不用name携带提交数据,data封装数据进行提交

    第一种方法

    login.html

    <body>
    
        {% csrf_token %}   #第一步
        用户名:<input type="text" id="username">
        密码:<input type="password" id="password">
        <button id="sub">提交</button>
        <span class="error"></span>
    
        <script src="{% static 'jquery.js' %}"></script>
        <script src="{% static 'jquery.cookie.js' %}"></script>
        <script>
    
            $("#sub").click(function(){
                var uname = $("#username").val();
                var pwd = $("#password").val();
                var csrf = $("[name=csrfmiddlewaretoken]").val();  #第二步
    
                $.ajax({
                    url:"{% url 'login' %}",
                    type:"post",
     第三步添加键值对 data:{username:uname,password:pwd,csrfmiddlewaretoken:csrf},
                    {#headers:{"X-CSRFToken":$.cookie('csrftoken')},#}
                    success:function (res) {
                        console.log(res);
                        if (res === "1"){
                            location.href = "/home/";
                        }else{
                            $(".error").text("用户名或密码错误")
                        }
                    }
                })
            })
        </script>
    

    views.py

    def login(request):
        if request.method == "GET":
            return render(request,"login.html")
        else:
            user = request.POST.get("username")
            pwd = request.POST.get("password")
            if user == "alex" and pwd == "123":
                return HttpResponse("1")
            else:
                # return redirect("login")
                return HttpResponse("0")
    

    第二种方法

    {#var csrf = $("[name=csrfmiddlewaretoken]").val();#}
        换成,内容都是等于随机验证的值
    var csrf = "{{ csrf_token }}";
    

    第三种方法

    自定义封装请求头
     url:"{% url 'login' %}",
                    type:"post",
                    {#data:{username:uname,password:pwd,csrfmiddlewaretoken:csrf},#}
                        修改成如下代码
                    data:{username:uname,password:pwd},
                    headers:{"X-CSRFToken":$.cookie('csrftoken')},
     # 其中headers中"X-CSRFToken"不可修改,$.cookie(键值)是cookie的取值方式,键写的是Request Cookies的名字,用此方法是一定引入 <script src="{% static 'jquery.cookie.js' %}"></script>文件
    

    form上传文件

    upload.html 文件

        <h1>文件上传</h1>
        <form action="" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            用户名:<input type="text" name="username">
            密码:<input type="password" name="password">
            头像:<input type="file" name="file" multiple>
            <input type="submit">
        </form>
    

    views.py文件

    from django.conf import settings
    #全局配置,一般不用自己的settings
    def upload(request):
        if request.method == "GET":
            return render(request,"upload.html")
        else:
            print(request.POST)       #得到post请求数据,queryset对象
            print(request.FILES)      #得到文件对象数据
            user = request.POST.get("username")
            pwd = request.POST.get("password")
            file_obj = request.FILES.get("file")
            # print(file_obj.name)
            with open(file_obj.name,"wb") as f:
                # for i in file_obj:   第一种接收方法
                #    f.write(i)
                for chunk in file_obj.chunks():  第二种接收方法
                    f.write(chunk)
    
            return HttpResponse("ok")
    

    其中,enctype="multipart/form-data",使上传文件时分段传送,/n /r 时分段接收,不至于一次接受过多的数据,撑爆内存,所以一定加上此属性。而chunks()方法默认一次返回大小为经测试为65536B,也就是64KB,最大为2.5M,是一个生成器,修改时应在全局settings文件修改;multiple属性,表示上传多个对象

    ajax上传文件

    在ajax上传文件时,没有enctype="multipart/form-data"上传格式,我们借助于FormData()对象实现

    processData:false, contentType:false, 这两个参数是告诉浏览器不要对我的数据进行任何加工,直接发送原始数据,否则报错

    upload.html 文件

        {% csrf_token %}
        用户名:<input type="text" id="username">
        密码:<input type="password" id="password">
        上传文件:<input type="file" id="file" multiple>
        <button id="sub">提交</button>
        <span class="error"></span>
    
        <script src="{% static 'jquery.js' %}"></script>
        <script src="{% static 'jquery.cookie.js' %}"></script>
        <script>
    
            $("#sub").click(function(){
                var formdata = new FormData();  #新建对象
                var uname = $("#username").val();
                var pwd = $("#password").val();
                var file_obj = $("[type=file]")[0].files[0];
    
                formdata.append("username",uname);
                formdata.append("passwodd",pwd);
                formdata.append("file",file_obj);
                {#以键和值的形式将数据封装到formdata中#}
                $.ajax({
                    url:"{% url 'upload' %}",
                    type:"post",
                    {#data:{username:uname,password:pwd},#}
                    data:formdata,
                    processData:false,
                    contentType:false,
                    headers:{"X-CSRFToken":$.cookie('csrftoken')},
                    success:function (res) {
                        console.log(res);
                        if (res === "1"){
                            location.href = "/home/";
                        }else{
                            $(".error").text("用户名或密码错误")
                        }
                    }
                })
            })
        </script>
    

    views.py

    from django.conf import settings
    #全局配置,一般不用自己的settings
    def upload(request):
        if request.method == "GET":
            return render(request,"upload.html")
        else:
            # print(request.POST)
            # print(request.FILES)
            # user = request.POST.get("username")
            # pwd = request.POST.get("password")
            file_obj = request.FILES.get("file")   # 接收的是data中的数据
            with open(file_obj.name,"wb") as f:
                # for i in file_obj:
                #    f.write(i)
                for chunk in file_obj.chunks():
                    f.write(chunk)
    
            return HttpResponse("ok")
    

    ajax数据交互

    jsontest.html文件

    {% load static %}   {# 固定写法,不可修改 #}
    <!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, initial-scale=1">
        <title>Bootstrap 101 Template</title>
    
    </head>
    <body>
        <h1>文件上传</h1>
    
        {% csrf_token %}
        用户名:<input type="text" id="username">
        密码:<input type="password" id="password">
        <button id="sub">提交</button>
        <span class="error"></span>
    
        <script src="{% static 'jquery.js' %}"></script>
        <script src="{% static 'jquery.cookie.js' %}"></script>
        <script>
    
            $("#sub").click(function(){               //绑定点击事件
                var uname = $("#username").val();     //jQuery前端获取提交的数据
                var pwd = $("#password").val();
    
                $.ajax({
                    url:"{% url 'jsontest' %}",     //执行函数
                    type:"post",				   // 执行方式
                    data:{username:uname,password:pwd},  // 通过data向后端提交数据
                    headers:{"X-CSRFToken":$.cookie('csrftoken')},  // 设置通过CSRF方式
                    success:function (res) {			// res接收后端传过来的Httpresponse对象数据
    
                        console.log(res,typeof res);  //{"status": 1001, "msg": "登陆失败"} string
                        var res = JSON.parse(res);
                        {#反序列化,将字符串类型数据转换为数组等原数据类型#}
                        console.log(res,typeof res);  //{status: 1001, msg: "登陆失败"}"object"
                        if (res.status === 1000){
                            {#js中字典取值的两种方式[]或者点#}
                            location.href = "/home/";
                            {#    页面跳转方法#}
                        }else{
                            $(".error").text(res["msg"]);
                            {# js中字典取值的两种方式[]或者点   #}
                        }
                    }
                })
            })
        </script>
    
    </body>
    </html>
    

    第二种反序列化方法

    ret_data_json = json.dumps(ret_data,ensure_ascii=False)
    #ensure_ascii=False 关闭ASCII
    return HttpResponse(ret_data_json,content_type="application/json")
    html中
    console.log(res,typeof res);  //{"status": 1001, "msg": "登陆失败"} “object”
    
    # content_type="application/json" 指定返回的消息格式,告诉ajax我返回的数据就是一个
    # json数据,ajax收到这个数据之后发现你指定了消息格式是json,就会直接调用ajax内部的封
    # 装的解析器对json数据进行反序列化,返回的就是js语言中的原数据类型,不需要自己反序列化了
    

    第三种方法

    return JsonResponse(ret_data)
    直接替换上边两句,传过去的就是原数据类型
    如果是非字典数据类型,则加一个属性
    return JsonResponse(ret_data,safe=False)
    
      ret = [1,2,3]
      return JsonResponse(ret,safe=False)
    

    views.py 文件

    import json
    def jsontest(request):
        if request.method == "GET":
            return render(request,"jsontest.html")
        else:
            username = request.POST.get("username")
            pwd = request.POST.get("password")
            ret_data = {"status":None,"msg":None}
            if username == "alex" and pwd == "123":
                ret_data["status"] = 1000
                ret_data["msg"] = "登陆成功"
    
            else:
                ret_data["status"] = 1001
                ret_data["msg"] = "登陆失败"
            ret_data_json = json.dumps(ret_data,ensure_ascii=False)
            #转换为字符串类型,ensure_ascii=False 关闭ASCII,识别中文
            return HttpResponse(ret_data_json)
    
    # return HttpResponse(ret_data)
    #HttpResponse返回的是字符串类型数据,这样返回得到statusmsg(键的拼接)
    

    视图响应方法四种

    from django.shortcuts import render,HttpResponse,redirect
    from django.http import JsonResponse
    
    render 返回一个html文件
    HttpResponse  返回一个字符串数据
    redirect 重定向,参数函数,一般返回另一个页面
    JsonResponse 直接将json数据返回给html文件,并已经反序列化
    只适用于数组是字典的类型,对于非字典类型数据,则需加上一个属性
    return JsonResponse(ret_data,safe=False)
    
      ret = [1,2,3]
      return JsonResponse(ret,safe=False)
    

    通过ajax删除数据

    相关知识

    注意前端删除只是删除显示,数据库数据没有删除,必须执行后端删除才可以,否则刷新数据不变

    https://www.runoob.com/jquery/jquery-dom-get.html

    1. jQuery attr() 方法用于获取标签中的属性值
    2. text() - 设置或返回所选元素的文本内容
    3. html() - 设置或返回所选元素的内容(包括 HTML 标记)
    4. val() - 设置或返回表单字段的值,post提交的数据
    5. ajax 依赖js才能执行

    第一种方法 后端删除

    url.py

    url(r'^ajaxbook_del/', views.ajaxauthor_del,name="ajaxauthor_del")
    

    views.py

    from django.http import JsonResponse
    def ajaxbook_del(request):
    
        author_id = request.POST.get('author_id')
        # 后端获取到的只是ajax传过去的数据,没有ajax不能如此获取,需要写成pk等在路径处获取
        obj = models.Author.objects.filter(pk=author_id)
        if not obj:
            return HttpResponse("数据不存在")
        obj.delete()
       return JsonResponse({'status':200,'msg':'ok'})
    

    show.html

    <button class="btn btn-danger ajaxbtn" author_id="{{ all_author.pk }}">ajax删除</button>
    {# ajax绑定事件不能设置id,相当于我每次点击id是相同的,而id是不允许相同,如果相同了只能触发第一个事件,也就只删除第一个#}
        
    <script src="{% static 'js/jquery.js' %}"></script>
    <script>
        $(".ajaxbtn").click(function () {
             var author_id = $(this).attr("author_id");
             // 这种获得标签内容的方法是前端方法
             $.ajax({
                 url:'{% url "ajaxauthor_del" %}',
                 type:"post",
                 data: {"author_id": author_id, 'csrfmiddlewaretoken': "{{ csrf_token }}"},
                  success:function (ret) {
                     location.href = "{% url 'author_list' %}";
                    }
                })
            })
    </script>
        
    第二种
        
        <script src="{% static 'js/jquery.js' %}"></script>
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
        <script src="{% static 'sw/sweetalert.min.js' %}"></script> //跟下边的不是一个文件
    
        <script>
        $(".ajaxbtn").on("click", function () {
            var ths = $(this);
    
            swal({
                title: "你确定要删除吗?",
                text: "删除可就找不回来了哦!",
                type: "warning",
                showCancelButton: true,
                confirmButtonClass: "btn-danger",
                confirmButtonText: "删除",
                cancelButtonText: "取消",
                closeOnConfirm: false
            },
                function () {
                    var author_id = ths.attr('author_id');
                    $.ajax({
                        url: '{% url "ajaxauthor_del" %}',
                        type: "post",
                        data: {"author_id": author_id, 'csrfmiddlewaretoken': "{{ csrf_token }}"},
                        success: function (data) {
                            if (data.status === 200) {
                                swal("删除成功!", "你可以准备跑路了!", "success");
                                // location.reload();
                                // console.log(1);
                                ths.parent().parent().remove();
                                location.href = "{% url 'author_list' %}";
    
                            } else {
                                // console.log(2);
                                swal("删除失败", "你可以再尝试一下!", "error")
                            }
                        }
                    })
                });
        })
        </script>
    

    第二种方法 前端删除

    url.py

    url(r'^ajaxauthor_del2/(d+)/', views.ajaxauthor_del2,name="ajaxauthor_del2")
    

    views.py

    from django.http import JsonResponse
    def ajaxbook_del2(request,n):
    
        obj = models.Author.objects.filter(pk=n).first()
        if not obj:
            return HttpResponse("数据不存在")
        obj.delete()
        return JsonResponse({'status':200,'msg':'ok'})
    

    show.html

    <a class="btn btn-danger btn-sm ajaxbtn2" url="{% url 'ajaxauthor_del2' all_author.pk %}">ajax2删除 </a>
    {# ajax绑定事件不能设置id,相当于我每次点击id是相同的,而id是不允许相同,如果相同了只能触发第一个事件,也就只删除第一个#}
        
    <script src="{% static 'js/jquery.js' %}"></script>
    <script>
       $('.ajaxbtn2').click(function () {
           var _this = $(this);   // 声明this代指的事件
           $.ajax({
                url: $(this).attr('url'),
                success: function (res) {
                    location.href = res;
                     if (res.status === 200) {
                      //  在前端删除数据
                      _this.parent().parent().remove();
                 // 父td  祖tr   // 根据当前事件查找到tr标签,删除
                      location.href = "{% url 'author_list' %}";
                 }
               }
            })
         })
    </script>
    第二种
    <script src="{% static 'js/jquery.js' %}"></script>
    <script src="{% static 'sw/sweetalert.min.js' %}"></script>   // 跟上边的不是一个插件,只是名字相同
    <script>
        $('.ajaxbtn2').click(function () {
            swal({
                title: "是否确定删除?",
                text: "删除后无法恢复",
                icon: "warning",
                buttons: true,
                dangerMode: true,
            }).then((willDelete) => {
                if (willDelete) {
    
                    $.ajax({
                        url: $(this).attr('url'),
                        // 指向函数this不会变
                        success: (res) => {
    
                            if (res.status === 200) {
                                //  在前端删除数据
                                swal("Poof! Your imaginary file has been deleted!", {
                                    icon: "success",
                                });
                                $(this).parent().parent().remove();
                                // console.log(1);
                                location.href = "{% url 'author_list' %}";
                            } else {
                                swal("Your imaginary file is safe!");
                                // console.log(2);
                            }
                        }
                    })
                }
            });
        })
    </script>
    
  • 相关阅读:
    Coding 初级教程(一)——用GitHub的GUI客户端对Coding的项目进行管理
    自己以前写的日记,现在公开(别的文章需要用)1
    7-网页,网站,微信公众号基础入门(微信配网_申请微信公众号)
    关于Keil4 转到 Keil5以后的一些错误解决
    6-网页,网站,微信公众号基础入门(PHP学习_1)
    5-网页,网站,微信公众号基础入门(配置网站--PHP配置上数据库)
    4-网页,网站,微信公众号基础入门(配置网站--下载安装PHP)
    3-网页,网站,微信公众号基础入门(学习网页_2)
    7-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(GPRS模块SSL连接MQTT)
    6-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(Wi-Fi模块SSL连接MQTT)
  • 原文地址:https://www.cnblogs.com/lvweihe/p/11885284.html
Copyright © 2011-2022 走看看