目录
- Ajax
- Ajax简介
- AJAX常见应用情景
- Ajax的优缺点
- 优点:
- 缺点:
- Ajax简单登录认证
- csrf认证
- form表单设置csrf_token
- Ajax设置csrf认证
- 文件上传
- 请求头Content-Type
- form表单上传文件
- Ajax的上传文件
- JsonResponse
- SweetAlert插件--对话框
Ajax
Ajax简介
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
? AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
特点:异步请求、局部刷新
异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
局部刷新:可以局部添加网页内容,如提示:用户名或者密码错误等。
AJAX常见应用情景
搜索引擎根据用户输入的关键字,自动提示检索关键字。
注册时的用户名的查重。
? 当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为输入的用户是否存在,最终服务器返回true表示用户名已经存在了,浏览器在得到结果后显示“用户名已被注册!”。
a.整个过程中页面没有刷新,只是局部刷新了;
b.在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;
提交数据,上传文件。
Ajax的优缺点
https://www.cnblogs.com/SanMaoSpace/archive/2013/06/15/3137180.html
优点:
- AJAX使用JavaScript技术向服务器发送异步请求;
- AJAX请求无须刷新整个页面;
- 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
缺点:
- 安全问题,不经意间会暴露比以前更多的数据和服务器逻辑
- 如果用户禁用了JS,网站就取不到数据
- AJAX干掉了Back和History功能,即对浏览器机制的破坏。用户通常会希望单击后退按钮能够取消他们的前一次操作,但是在Ajax应用程序中,这将无法实现。
- AJAX不能很好支持移动设备。
Ajax简单登录认证
用form表单登录,提交数据会刷新页面。ajax不会刷新。
login.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"> </head> <body> <div style="width: 500px;height:200px;background-color: #4ba7ff;margin-top: 180px; margin-left: 350px;"> <div style="padding-top:50px;"> <div class="form-group"> <label class="col-sm-2 control-label">用户名</label> <div class="col-sm-10"> <input type="text" class="form-control" placeholder="请输入用户名" id="username"> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">密码</label> <div class="col-sm-10"> <input type="password" class="form-control" placeholder="请输入密码" id="password"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default" id="sub">登 录</button> <span id="error" style="color: red"></span> </div> </div> </div> </div> </body> <script src="http://img.558idc.com/uploadfile/allimg/210625/13032MT1-0.jpg"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script> <script > $('#sub').click(function () { // 绑定点击事件,一点击 登录 会将数据提交给后端,不会刷新页面 var username=$('#username').val(); var password=$('#password').val(); $.ajax({ url:'{% url "login" %}', // type:'post', data:{'user':username,'pwd':password}, // data会携带数据提交到url路径 res:是接收后端返回的数据 success:function (res) { if(res === '1'){ // 表示登录成功,跳转到home页面 location.href='{% url "home" %}'} else{ // 登录失败,局部刷新,添加提示 $('#error').text('用户名或密码错误!') } } }) }) </script> </html>
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login, name='login'), url(r'^home/', views.home, name='home'),
views.py
from django.shortcuts import render, HttpResponse, redirect def login(request): if request.method=='GET': return render(request, 'login.html') else: user = request.POST.get('user') # 获取ajax中data携带的数据 pwd = request.POST.get('pwd') if user == 'yan' and pwd == '123': # 假设用户名与密码 return HttpResponse('1') # 登录成功返回1 else: return HttpResponse('0') # 登录成功返回0 def home(request): return render(request, 'home.html')
csrf认证
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。攻击者通过HTTP请求将数据传送到服务器,从而盗取回话的cookie。盗取回话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。
? 所以解决csrf攻击的最直接的办法就是生成一个随机的csrftoken值,保存在用户的页面上,每次请求都带着这个值过来完成校验。
token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。
form表单设置csrf_token
{% csrf_token %} 标签,加上这个标签,模板渲染之后就是一个隐藏的input标签,提交数据时,会随数据一起提交给后端。
<input type="hidden" name=‘csrfmiddlewaretoken’ values=‘dkjdkasiofaad...’>
<form action="" method="post"> {% csrf_token %} // form表单里面加上这个标签,模板渲染之后就是input标签 <div style="width: 500px;height:200px;background-color: #4ba7ff;margin-top: 180px; margin-left: 350px;"> <div style="padding-top:50px;"> <div class="form-group"> <label class="col-sm-2 control-label">用户名</label> <div class="col-sm-10"> <input type="text" class="form-control" placeholder="请输入用户名" id="username" name='username'> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">密码</label> <div class="col-sm-10"> <input type="password" class="form-control" placeholder="请输入密码" id="password" name='password'> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default" id="sub">登 录</button> <span id="error" style="color: red"></span> </div> </div> </div> </div> </form>
Ajax设置csrf认证
方式一:
通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
// 在body标签中,增加 {% csrf_token %} 标签 <script > $('#sub').click(function () { var username=$('#username').val(); var password=$('#password').val(); // csrf方式一: var csrf=$('[name=csrfmiddlewaretoken]').val(); // 使用jQuery取出csrfmiddlewaretoken的值, $.ajax({ url:'{% url "login" %}', type:'post', data:{'user':username,'pwd':password, "csrfmiddlewaretoken":csrf}, // data会携带数据 success:function (res) { if(res === '1'){ location.href='{% url "home" %}'} else{ console.log(res); $('#error').text('用户名或密码错误!') } } }) }) </script>
方式二:
用 {{ csrf_token }} 变量直接获取csrfmiddlewaretoken的值
<script > $('#sub').click(function () { var username=$('#username').val(); var password=$('#password').val(); // csrf方式二: var csrf = '{{ csrf_token }}'; $.ajax({ url:'{% url "login" %}', type:'post', data:{'user':username,'pwd':password, "csrfmiddlewaretoken":csrf}, // data会携带数据 success:function (res) { if(res === '1'){ location.href='{% url "home" %}'} else{ console.log(res); $('#error').text('用户名或密码错误!') } } }) }) </script>
方式三:
引入:jquery.cookie.js;下载:http://plugins.jquery.com/cookie/
通过获取返回的cookie中的字符串 放置在请求头中发送。
? Ajax里面还有一个参数是headers,自定制请求头,可以将csrf_token加在这里,发contenttype类型数据的时候,csrf_token就可以这样加。
<script > $('#sub').click(function () { var username=$('#username').val(); var password=$('#password').val(); $.ajax({ url:'{% url "login" %}', type:'post', data:{'user':username,'pwd':password, "csrfmiddlewaretoken":csrf}, // data会携带数据 // csrf 方式三: headers:{ "X-CSRFToken":$.cookie('csrftoken'), }, // 必须引入jquery.cookie.js success:function (res) { if(res === '1'){ location.href='{% url "home" %}'; {#$('#error').text('登录成功!'); }#} } else{ {#console.log(res);#} $('#error').text('用户名或密码错误!') } } }) }) </script>
注意:
如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。
这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。
django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def login(request): pass
文件上传
请求头Content-Type
服务端告诉浏览器,数据是以什么封装的。否则浏览器不知道怎样解开数据。
1. Content-Type: application/x-www-form-urlencoded;charset=utf-8 # 最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个。 user=yan&pwd=123 #这就是上面这种content-type规定的数据格式,后端对应这个格式来解析获取数据,不管是get方法还是post方法,都是这样拼接数据,大家公认的一种数据格式. 2. Content-Type:multipart/form-data; # form表单设置enctype属性时,post提交数据的方式 3. Content-Type:application/json # 告诉浏览器 服务端消息主体是序列化后的 JSON 字符串。
form表单上传文件
在form中加 enctype="multipart/form-data"。form表单不支持发json类型的content-type格式的数据,而ajax什么格式都可以发,也是ajax应用广泛的一个原因。
<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"> <input type="submit"> </form>
views.py
from django.conf import settings # 能用全局settings获取一些配置,如路径等 def upload(request): if request.method == 'GET': print(settings.BASE_DIR) #/static/ return render(request,'upload.html') else: # print(request.POST) # print(request.FILES) uname = 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) # 方式二:chunks()默认一次返回大小为65536B,也就是64KB,最大为2.5M的数据,是一个生成器 for chunk in file_obj.chunks(): f.write(chunk) return HttpResponse('ok')
通过js来找文件对象
Ajax的上传文件
<script > $('#sub').click(function () { // 创建一个对象 var formdata = new FormData(); var user = $('#username').val(); var pwd = $('#password').val(); var file_obj = $('[type=file]')[0].files[0]; // js获取文件对象 // 封装 formdata.append('username',user); formdata.append('password',pwd); formdata.append('file',file_obj); $.ajax({ url:'{% url "upload" %}', type:'post', // data:{username:user,password:pwd,csrfmiddlewaretoken:csrf}, //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'){ // $('.error').text('登录成功'); location.href = '/home/'; // http://127.0.0.1:8000/home/ }else{ $('.error').text('用户名密码错误!'); } } }) }) </script>
views.py
def upload(request): if request.method == 'GET': return render(request,'upload.html') else: # print(request.POST) # print(request.FILES) uname = 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) # 方式二:chunks()默认一次返回大小为65536B,也就是64KB,最大为2.5M的数据,是一个生成器 for chunk in file_obj.chunks(): f.write(chunk) return HttpResponse('ok')
JsonResponse
发送json类型的数据
from django.http import JsonResponse username = request.POST.get('username') pwd = request.POST.get('password') ret_data = {'status':None,'msg':None} print('>>>>>',request.POST) #<QueryDict: {'{"username":"123","password":"123"}': ['']}> if username == 'chao' and pwd == '123': ret_data['status'] = 1000 # 状态码 ret_data['msg'] = '登录成功!' else: ret_data['status'] = 1001 # 状态码 ret_data['msg'] = '登录失败!' # 方式一 ,关闭ensure_ascii后不乱码 # ret_data_json = json.dumps(ret_data,ensure_ascii=False) # return HttpResponse(ret_data_json) # 方式二,指定响应头 # return HttpResponse(ret_data_json,content_type='application/json') # 方式三 return JsonResponse(ret_data) # 非字典类型数据,需要加上 safe=False参数,否则认为是不合法的 #ret_data=[0,1,'a'] #return JsonResponse(ret_data, safe=False)
jsontest.html
<script> $.ajax({ url:'{% url "jsontest" %}', type:'post', // data:{username:uname,password:pwd,csrfmiddlewaretoken:csrf}, //序列化 //data:JSON.stringify({username:uname,password:pwd}), data:{username:uname,password:pwd}, headers:{ // contentType:'application/json', "X-CSRFToken":$.cookie('csrftoken'), }, success:function (res) { {#console.log(res,typeof res); // statusmsg {"status": 1001, "msg": "登录失败"}#} // 方式一:反序列化 {#var res = JSON.parse(res); //-- json.loads()#} // 方式二、三 console.log(res,typeof res); //直接就是反序列化之后的了 //JSON.stringify() -- json.dumps if (res.status === 1000){ // $('.error').text('登录成功'); location.href = '/home/'; // http://127.0.0.1:8000/home/ } else{ $('.error').text(res.msg); } } }) </script>
SweetAlert插件--对话框
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{% static 'bootstrap-3.3.0-dist/dist/css/bootstrap.min.css' %}"> <link rel="stylesheet" href="{% static 'bootstrap-sweetalert-master/dist/sweetalert.css' %}"> </head> <body> <div> <button class="btn btn-danger">删除</button> </div> </body> <script src="{% static 'bootstrap-3.3.0-dist/dist/jQuery/jquery-3.1.1.js' %}"></script> <script src="{% static 'bootstrap-3.3.0-dist/dist/js/bootstrap.min.js' %}"></script> <script src="{% static 'bootstrap-sweetalert-master/dist/sweetalert.js' %}"></script> <script> $(".btn-danger").on("click", function () { swal({ title: "你确定要删除吗?", text: "删除可就找不回来了哦!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "我已经下定决心", cancelButtonText: "容我三思", closeOnConfirm: false }, function () { var deleteId = $(this).parent().parent().attr("data_id"); $.ajax({ url: "/delete_book/", type: "post", data: {"id": deleteId}, success: function (data) { console.log(data,typeof data); if (data === '1') { swal("删除成功!", "你可以准备跑路了!", "success"); } else { swal("删除失败", "你可以再尝试一下!", "error") } } }) }); }) </script> </html>