AJAX
AJAX
AJAX之预备知识:JSON
什么是 JSON ?
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式。
- JSON 独立于语言 *
- JSON 具有自我描述性,更易理解
* JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
stringify与parse方法
JavaScript中关于JSON对象和字符串转换的两个方法:
JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象。
JSON.parse('{"name":"Eric","age":18}');// 将字符串解析为JavaScript的字典对象
执行结果如下:
JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。
JSON.stringify({"name":"Eric","age":18});// 将JavaScript的字典对象转为为字符串
执行结果如下:
和XML的比较
JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。
JSON 格式有两个显著的优点:书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。
XML和JSON都使用结构化方法来标记数据,下面来做一个简单的比较。
中国部分省市数据表示如下:
<?xml version="1.0" encoding="utf-8"?> <country> <name>中国</name> <province> <name>黑龙江</name> <cities> <city>哈尔滨</city> <city>大庆</city> </cities> </province> <province> <name>广东</name> <cities> <city>广州</city> <city>深圳</city> <city>珠海</city> </cities> </province> <province> <name>台湾</name> <cities> <city>台北</city> <city>高雄</city> </cities> </province> <province> <name>新疆</name> <cities> <city>乌鲁木齐</city> </cities> </province> </country>
{ "name": "中国", "province": [{ "name": "黑龙江", "cities": { "city": ["哈尔滨", "大庆"] } }, { "name": "广东", "cities": { "city": ["广州", "深圳", "珠海"] } }, { "name": "台湾", "cities": { "city": ["台北", "高雄"] } }, { "name": "新疆", "cities": { "city": ["乌鲁木齐"] } }] }
由上面的两段代码可以看出,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。
AJAX简介
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
示例
页面输入两个整数,通过AJAX传输到后端计算出结果并返回。
<!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>AJAX局部刷新实例</title> </head> <body> <!--两数求和并在第三个输入框显示--> <input type="text" id="i1">+ <input type="text" id="i2">= <input type="text" id="i3"> <input type="button" value="AJAX提交" id="b1"> <script src="/static/jquery-3.2.1.min.js"></script> <script> $("#b1").on("click", function () { $.ajax({ url:"/ajax_add/", type:"GET", data:{"i1":$("#i1").val(),"i2":$("#i2").val()}, success:function (data) { $("#i3").val(data); } }) }) </script> </body> </html>
def ajax_demo1(request): return render(request, "ajax_demo1.html") def ajax_add(request): i1 = int(request.GET.get("i1")) i2 = int(request.GET.get("i2")) ret = i1 + i2 return JsonResponse(ret, safe=False)
urlpatterns = [ path('ajax_add/', views.ajax_add), path('ajax_demo1/', views.ajax_demo1), ]
AJAX常见适用和不适用情景
Ajax适用场景
- 表单驱动的交互
- 深层次的树的导航
- 快速的用户与用户间的交流响应
- 类似投票、yes/no等无关痛痒的场景
- 对数据进行过滤和操纵相关数据的场景
- 普通的文本输入提示和自动完成的场景
Ajax不适用场景
- 部分简单的表单
- 搜索
- 基本的导航
- 替换大量的文本
- 对呈现的操纵
AJAX的优缺点
(1).AJAX的优点
- 无刷新更新数据。
- 异步与服务器通信。AJAX使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。优化了Browser和Server之间的沟通,减少不必要的数据传输、时间及降低网络上数据流量。
- 前端和后端负载平衡。AJAX可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。AJAX的原则是“按需取数据”,可以最大程度的减少冗余请求和响应对服务器造成的负担,提升站点性能。
- 基于标准被广泛支持。AJAX 基于标准化的并被广泛支持的技术,不需要下载浏览器插件或者小程序,但需要客户允许JavaScript在浏览器上执行。随着Ajax的成熟,一些简化 Ajax使用方法的程序库也相继问世。
- 界面与应用分离。Ajax使WEB中的界面与应用分离(也可以说是数据与呈现分离),有利于分工合作、减少非技术人员对页面的修改造成的WEB应用程序错误、提高效率、也更加适用于现在的发布系统。
(2).AJAX的缺点
- AJAX干掉了Back和History功能,即对浏览器机制的破坏。在动态更新页面的情况下,用户无法回到前一个页面状态,因为浏览器仅能记忆历史记录中的静态页面。一个被完整读入的页面与一个已经被动态修改过的页面之间的差别非常微妙;用户通常会希望单击后退按钮能够取消他们的前一次操作,但是在Ajax应用程序中,这将无法实现。后退按钮是一个标准的web站点的重要功能,但是它没法和js进行很好的合作。这是Ajax所带来的一个比较严重的问题,解决用户希望的能够通过后退来取消前一次操作的方法:用过Gmail的知道,Gmail下面采用的Ajax技术解决了这个问题,在Gmail下面是可以后退的,但是,它也并不能改变Ajax的机制,它只是采用的一个比较笨但是有效的办法,即用户单击后退按钮访问历史记录时,通过创建或使用一个隐藏的IFRAME来重现页面上的变更。但是它所带来的开发成本是非常高的,并与Ajax框架所要求的快速开发是相背离的。这是Ajax所带来的一个非常严重的问题。使用动态页面更新使得用户难于将某个特定的状态保存到收藏夹中,解决方案:大部分都使用URL片断标识符(通常被称为 锚点,即URL中#后面的部分)来保持跟踪,允许用户回到指定的某个应用程序状态。(许多浏览器允许JavaScript动态更新锚点,这使得Ajax应用程序能够在更新显示内容的同时更新锚点。)
- AJAX的安全问题。AJAX 技术给用户带来很好的用户体验的同时也对IT企业带来了新的安全威胁,Ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比 以前更多的数据和服务器逻辑。Ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。还有Ajax也难以避免一些已知 的安全弱点,诸如跨站点脚本攻击、SQL注入攻击和基于Credentials的安全漏洞等等。
- 对搜索引擎支持较弱。如果使用不当,AJAX会增大网络数据的流量,从而降低整个系统的性能。
- 破坏程序的异常处理机制。至少从目前看来,像Ajax.dll,Ajaxpro.dll这些Ajax框架是会破坏程序的异常机制的。
- 违背URL和资源定位的初衷。例如,我给你一个URL地址,如果采用了Ajax技术,也许你在该URL地址下面看到的和我在这个URL地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。
- AJAX不能很好支持移动设备。一些手持设备(如手机、PDA等)现在还不能很好的支持Ajax,比如说我们在手机的浏览器上打开采用Ajax技术的网站时,它目前是不支持的。
- 客户端过肥,太多客户端代码造成开发上的成本。编写复杂、容易出错 ;冗余代码比较多(层层包含js文件是AJAX的通病,再加上以往的很多服务端代码现在放到了客户端);破坏了Web的原有标准。
jQuery实现的AJAX
<!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>ajax test</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> </head> <body> <button id="ajaxTest">AJAX 测试</button> <script> $("#ajaxTest").click(function () { $.ajax({ url: "/ajax_test/", type: "POST", data: {username: "Eric", password: 3452345}, success: function (data) { alert(data) } }) }) </script> </body> </html>
def ajax_test(request): user_name = request.POST.get("username") password = request.POST.get("password") print(user_name, password) return HttpResponse("OK")
$.ajax参数
注意:data参数中的键值对,如果值值不为字符串,需要将其转换成字符串类型。
$("#b1").on("click", function () { $.ajax({ url:"/ajax_add/", type:"GET", data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe": JSON.stringify([1, 2, 3])}, success:function (data) { $("#i3").val(data); } }) })
var b2 = document.getElementById("b2"); b2.onclick = function () { // 原生JS var xmlHttp = new XMLHttpRequest(); xmlHttp.open("POST", "/ajax_test/", true); xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlHttp.send("username=q1mi&password=123456"); xmlHttp.onreadystatechange = function () { if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { alert(xmlHttp.responseText); } }; };
AJAX请求如何设置csrf_token
$.ajax({ url: "/cookie_ajax/", type: "POST", data: { "username": "Eric", "password": 3453245, "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中 }, success: function (data) { console.log(data); } })
$.ajax({ url: "/cookie_ajax/", type: "POST", headers: {"X-CSRFToken": $.cookie('csrftoken')}, // 从Cookie取csrftoken,并设置到请求头中 data: {"username": "Eric", "password": 34532145}, success: function (data) { console.log(data); } })
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
注意:
如果使用从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
AJAX上传文件
XMLHttpRequest 是一个浏览器接口,通过它,我们可以使得 Javascript 进行 HTTP (S) 通信。XMLHttpRequest 在现在浏览器中是一种常用的前后台交互数据的方式。2008年 2 月,XMLHttpRequest Level 2 草案提出来了,相对于上一代,它有一些新的特性,其中 FormData 就是 XMLHttpRequest Level 2 新增的一个对象,利用它来提交表单、模拟表单提交,当然最大的优势就是可以上传二进制文件。下面就具体
首先看一下formData的基本用法:FormData对象,可以把所有表单元素的name与value组成一个queryString,提交到后台。只需要把 form 表单作为参数传入 FormData 构造函数即可。
// 上传文件示例 $("#b3").click(function () { var formData = new FormData(); formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); formData.append("f1", $("#f1")[0].files[0]); $.ajax({ url: "/upload/", type: "POST", processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 data: formData, success:function (data) { console.log(data) } }) })
或者使用:
var form = document.getElementById("form1"); var fd = new FormData(form);
这样也可以直接通过ajax 的 send() 方法将 fd 发送到后台。
注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。
序列化
Django内置的serializers
def books_json(request): book_list = models.Book.objects.all()[0:10] from django.core import serializers ret = serializers.serialize("json", book_list) return HttpResponse(ret)
SweetAlert插件示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>展示</title> <link rel="stylesheet" href="/static/bootstrap.min.css"> <link rel="stylesheet" href="/static/sweetalert.css"> </head> <body> <div class="container"> <div class="row col-md-6 col-md-offset-3"> <div class="panel panel-primary"> <div class="panel-heading">书目</div> <div class="panel-body"> <table class="table table-bordered"> <thead> <tr> <th>id</th> <th>序号</th> <th>出版社</th> <th>操作</th> </tr> </thead> <tbody> {% for show in show_list %} <tr> <th>{{ show.id }}</th> <th>{{ forloop.counter }}</th> <th>{{ show.name }}</th> <th><button class="btn btn-danger del">删除</button></th> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </div> </body> </html>
<script src="/static/jQuery-3.2.1.min.js"></script> <script src="/static/bootstrap.min.js"></script> <script src="/static/sweetalert.min.js"></script> <script src="/static/csrf_ajax.js"></script> <script> $(".del").on('click', function () { var $id=$(this).parent().parent(); var id_num=$($id).children().eq(0).text(); alert(id_num) swal({ title: "你确定要删除吗?", text: "删除了就不会恢复此文件了", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "是,删了他", cancelButtonText: "不,取消", closeOnConfirm: false }, function () { $.ajax({ url:'/swal/', type:'post', data:{"del_id":id_num}, success:function (arg) { swal(arg, "文件已删.", "success"); $($id).remove(); } }) }) }); </script>
def swal(request): del_id=request.POST.get('del_id') print(del_id) if del_id: models.Publisher.objects.get(id=del_id).delete() return HttpResponse('删除') ret = models.Publisher.objects.all() return render(request, 'index.html',{"show_list":ret})
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('swal/',views.swal) ]