ajax2

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给浏览器

![

](assets/1570708314067.png)

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 请求认证

第一种方法

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")
        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();
            var pwd = $("#password").val();

            $.ajax({
                url:"{% url 'jsontest' %}",
                type:"post",
                data:{username:uname,password:pwd},
                headers:{"X-CSRFToken":$.cookie('csrftoken')},
                success:function (res) {

                    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)
posted @ 2019-10-12 17:15  lvweihe  阅读(534)  评论(0编辑  收藏  举报