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 请求认证
第一种方法
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) 直接替换上边两句,传过去的就是原数据类型
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