AJAX
AJAX(Asynchronous javascript And XML)翻译成中文就是"异步的Javascript和XML"。
即使用JavaScript语言与服务器进行异步交互,传输的数据为XML(当前不只是XML)
AJAX 不是新的编程语言,而是一种使用现有标准的新方法
AJAX最大的有点在于,整个页面不重新加载的情况下,可以与服务器进行交互数据并且更新部分数据内容。
(这一特点 用户在不知不觉中完成了前后端 请求和响应的过程)
AJAX不需要任何浏览器插件,只需要用户允许JavaScript在浏览器执行。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发送第二个请求。
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发送第二个请求。
示例
页面输入内容,通过AJAX传输到后端进行计算并返回结果
index.html
<!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>Title</title>
</head>
<body>
{% csrf_token %}
<input type="text" name="i1" value="{{ i1 }}"> +
<input type="text" name="i2" value="{{ i2 }}"> =
<input type="text" name="i3" value="{{ i3 }}">
<button id="b1">计算</button>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="/static/ajax_setup.js"></script>
<script>
$(\'#b1\').click(function () {
// 获取前面input框 计算出的值 发送给后端
// 发送ajax请求
$.ajax({
url:\'/calc/\', // 请求的地址
type:\'post\', // 请求方式 默认不写为get请求
data: {
l1: $(\'[name="i1"]\').val(),
l2: $(\'[name="i2"]\').val(),
}, // 提交的数据
success:function (res) {
$(\'[name="i3"]\').val(res)
} // 响应成功,回调的函数 res响应体
})
});
</script>
</body>
</html>
views.py
def index(request):
return render(request,\'index.html\')
def calc(request):
l1 = request.POST.get(\'l1\')
l2 = request.POST.get(\'l2\')
return HttpResponse(int(l1) + int(l2))
urls.py
urlpatterns = [
url(r\'^admin/\', admin.site.urls),
url(r\'^index/\', views.index, name=\'index\'),
url(r\'^calc/\', views.calc,name=\'calc\'),
]
AJAX常见应用情景
索引擎根据用户输入的关键字,自动提示检索关键字。
还有一个很重要的应用场景就是注册时候的用户名的查重。
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。
- 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
- 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在得到结果后显示“用户名已被注册!”。
- 整个过程中页面没有刷新,只是局部刷新了;
- 在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;
AJAX的优缺点
优点:
- AJAX使用JavaScript技术向服务器发送异步请求;
- AJAX请求无须刷新整个页面;
- 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
$.ajax参数
$("#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);
}
})
})
JS实现ajax
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
方式一
通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
$.ajax({
url: "/cookie_ajax/",
type: "POST",
data: {
"username": "Q1mi",
"password": 123456,
"csrfmiddlewaretoken": $("[name = \'csrfmiddlewaretoken\']").val() // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中
},
success: function (data) {
console.log(data);
}
})
方式二
通过获取返回的cookie中的字符串 放置在请求头中发送。
注意:需要引入一个jquery.cookie.js插件
$.ajax({
url: "/cookie_ajax/",
type: "POST",
headers: {"X-CSRFToken": $.cookie(\'csrftoken\')}, // 从Cookie取csrftoken,并设置到请求头中
data: {"username": "Q1mi", "password": 123456},
success: function (data) {
console.log(data);
}
})
或者用自己写一个getCookie方法:
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\');
每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为ajax请求统一设置。
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
更多细节详见:Djagno官方文档中关于CSRF的内容
AJAX上传文件
// 上传文件示例
$("#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)
}
})
})
views.py
def file_upload(request):
if request.method == \'POST\':
print(request.FILES)
f1 = request.FILES.get(\'f2\')
with open(f1.name,mode=\'wb\') as f:
for i in f1.chunks():
f.write(i)
return render(request,\'file_upload.html\')
例子 用户名是否已注册
在注册表单中,当用户填写了用户名后,把光标移开后,会自动向服务器发送异步请求。服务器返回这个用户名是否已经被注册过。
urls.py
urlpatterns = [
...
url(r\'^regist/$\',views.Register.as_view(), name=\'register\'),
url(r\'^user_test/$\',views.user_test,name=\'user_test\'),
...
]
views.py
def user_test(request):
register = request.POST.get(\'user\')
print(register)
userobj = models.User.objects.filter(username=register)
if userobj:
return HttpResponse(\'用户已存在\')
return HttpResponse(\'\')
class Register(View):
http_method_names = [\'get\', \'post\']
def get(self, request, *agrs, **kwargs):
return render(request, \'register.html\')
def post(self, request, *args, **kwargs):
reg_user = request.POST.get(\'username\')
reg_passwd1 = request.POST.get(\'password1\')
reg_passwd2 = request.POST.get(\'password2\')
if reg_passwd2 != reg_passwd1:
return render(request, \'register.html\', {\'password_error\': \'密码输入不匹配\'})
models.User.objects.create(username=reg_user, password=reg_passwd2)
return redirect(\'login\')
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
{% load static %}
<title>注册页面</title>
</head>
<body>
<form class="text-center form-signin" action="" method="POST">
<span class=" iconfont"></span>
<div class="form-group row">
<label for="inputPassword6" class="col-sm-3 col-form-label col-form-label-lg">Username</label>
<input type="text" id="username" class="form-control
form-control-sm" aria-describedby="passwordHelpInline" name="username">
<br>
<small id="passwordHelpInline" class="">{{ cc }}</small>
</div>
<div class="form-group row">
<label for="inputPassword6" class="col-sm-2 col-form-label col-form-label-lg">Password</label>
<input type="password" id="inputPassword6" class="form-control form-control-sm"
aria-describedby=" passwordHelpInline" name="password1">
<small id="passwordHelpInline" class="text-muted">
请输入注册密码
</small>
</div>
<div class="form-group row">
<label for="inputPassword6" class="col-sm-2 col-form-label col-form-label-lg">Renew password</label>
<input type="password" id="inputPassword7" class="form-control
form-control-sm" aria-describedby="passwordHelpInline" name="password2">
<small id="passwordHelpInline" class="text-muted">
请重新输入密码
</small>
</div>
<span style="color: red;" class="text-center ">{{ password_error }} </span>
<button class="btn btn-lg btn-primary btn-block" type="submit">注册</button>
</form>
</body>
<script src="/static/plugins/jQuery3.4.1.js"></script>
<script src="/static/plugins/ajax_setup.js"></script>
<script src="/static/js/test.js"></script>
</html>
test.js
$(\'#username\').focus(function () {
var a = $(\'#passwordHelpInline\');
a.text(\'请输入注册用户!\');
a.css(\'color\',\'red\',\'font-size\',\'14\')
});
// 用户失去焦点触发ajax
$(\'#username\').blur(function () {
var input_user = $(\'#username\').val();
if (input_user.length === 0){
$(\'#passwordHelpInline\').text(\'不能为空!\')
} else {
$.ajax({
url: \'/user_test/\',
type: \'post\',
data: {
user: input_user
},
success: function (res) {
var a = $(\'#passwordHelpInline\');
a.text(res)
}
})
}
});
SweetAlert插件
https://sweetalert.js.org/guides/
$(".btn-danger").click(function () {
swal({
title: "你确定要删除吗?",
text: "一旦删除 赵臻儿子都帮你弄不回来!!!",
icon: "warning",
buttons: true,
dangerMode: true,
})
.then((willDelete) => {
if (willDelete) {
$.ajax({
url: $(this).attr(\'href\'),
type: \'get\',
success: (res) => {
if (res.status) {
$(this).parent().parent().remove();
swal("删除成功", {
icon: "success",
});
}
}
});
} else {
swal("欢迎再度光临!!");
}
});
});