一个动态网站是需要前端和后端进行数据交互。
什么是Ajax
Ajax是一种用于创建快速动态网页的技术。Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。
- AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
- 传统的网页(不使用 Ajax)如果需要更新内容,必需重载整个网页面。
- AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
ajax目的:提高用户体验,较少网络数据的传输量。
Ajax工作原理
网页DOM对象可以精确地对网页中的部分内容进行操作、XML作为单纯的数据存储载体使得客户端与服务器交换的只是网页内容的数据而没有网页样式等等的附属信息、XMLHttpRequest是与浏览器本身内置的request相互独立的与服务器交互的请求对象。
Ajax使用
- 创建XMLHttpRequest对象,也就是创建一个异步调用对象。
var xhr;
if (window.XMLHttpRequest) { //检查浏览器的XMLHttpRequest属性,如果为真则支持XMLHttpRequest
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xhr=new XMLHttpRequest();
} else {
// IE6, IE5 浏览器执行代码
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
2.向服务器发送请求
xhr.open(method,url,async);
send(string); //post请求时才使用字符串参数,否则不用带参数。
- method:请求的类型,常见的get或post方法
- url:向服务器请求的地址
- async:true(异步)或 false(同步),默认为true异步
get方式:
xhr.open('GET','/articles/?page='+ page);
xhr.send();
post方式:
xhr.open('POST', "/articles/" + article_id + "/likes/");
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8"); //必须写在open和send中间
xhr.send("key=value&key2=value2");
注意:
1)post请求一定要设置请求头的格式内容;
2)post请求参数放在send里面,即请求体.
- 服务器响应
ajax发起请求,django后端通过url规则进行匹配找到对应的视图进行处理,然后返回处理后的结果给后端,比如上面发起的是post请求,对应url在django中匹配的是article_likes
视图函数
path(r'<int:article_id>/likes/', article_likes, name='article_likes'),
article_likes
视图函数
def article_likes(request, article_id):
article = get_object_or_404(Article, pk=article_id)
# 判断是否同一个IP点赞,若是重复则不能继续点赞,反之点赞数也要相加
if 'HTTP_X_FORWARDED_FOR' in request.META: # request.META.has_key('HTTP_X_FORWARDED_FOR'):新版取消了has_key改用in判断
ip = request.META['HTTP_X_FORWARDED_FOR']
else:
ip = request.META['REMOTE_ADDR']
params = {'ip': ip, 'article_id': article_id}
# 有就取这个数据,如果没有就创建数据,返回元组(<Column: 关于>, True)
article_likes_tuple = ArticleLikeDetail.objects.get_or_create(**params)
article_likes_instance, article_likes_created_bolean = article_likes_tuple
if article_likes_created_bolean: # 如果新创建了
article.increase_likes() # 点赞数+1
add_flag = True
else: # 如果存在则
add_flag = False
likes_nums = article.like_num
result = {'likes_nums': likes_nums, 'add_flag': add_flag}
return JsonResponse(result)
django后端根据前端ajax的请求进行相应处理,并返回处理结果。
关于JsonResponse
class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None,**kwargs)
这个类是HttpRespon的子类,它主要和父类的区别在于:
1.它的默认Content-Type 被设置为: application/json;
2.第一个参数,data应该是一个字典类型,当 safe 这个参数被设置为:False ,那data可以填入任何能被转换为JSON格式的对象,比如list, tuple, set。 默认的safe 参数是 True. 如果你传入的data数据类型不是字典类型,那么它就会抛出 TypeError的异常。
3.json_dumps_params参数是一个字典,它将调用json.dumps()方法并将字典中的参数传入给该方法。
#如果这样返回,ajax还需要进行json解析
#views.py
return HttpResponse(json.dumps({"msg":"ok!"}))
#index.html
var data=JSON.parse(data) //先通过JSON.parse 将 JSON 字符串转换成对象。
console.log(data.msg);
#如果这样返回,两边都不需要进行json的序列化与反序列化,ajax接受的直接是一个对象
#views.py
from django.http import JsonResponse
return JsonResponse({"msg":"ok!"})
#index.html
console.log(data.msg);
javascript与python序列化和反序列化之间的转换:
Javascript object {name:"xiaoming"} ==> json的转换方式
JSON.stringify(data) ==> json.dumps
JSON.parse(data) ==> json.loads()
前端根据服务器相应进行相应处理。
前端数据获取:
responseText 获得字符串形式的响应数据。
responseXML 获得XML 形式的响应数据。
目前xml格式已经用的不多,json用的比较多,可以通过将responseText转换为对象进行操作。
分两种情况处理,同步或异步
1.同步情况,前端发起请求需要等服务器后端处理完返回才能继续运行下个流程。
xhr.open('GET','/articles/?page='+ page);
xhr.send();
let res = JSON.parse(xhr.responseText); //object,将一个 JSON 字符串转换为对象
直接在send()后面处理返回来的数据。
2.异步情况,前端发起完请求就不管,可以继续下一个流程,等服务器处理完会调用。 异步处理相对比较麻烦,要在请求状态改变事件中处理。
注册回调函数onreadystatechange
,发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态,XMLHttpRequest对象提供了onreadyStateChange事件实现这一功能。这类似于回调函数的做法。
onreadyStateChange事件是在readyState属性发生改变时触发的,readyState的值表示了当前请求的状态,在事件处理程序中可以根据这个值来进行不同的处理。
readyState有五种可取值
通常在事件中判断readyState的值是在请求完毕时才做处理,status存储了服务器端返回的Http请求响应代码,它表示请求的处理结果。
status:
等待请求处理成功,然后再进行局部刷新。
//注册回调函数
//请求响应回来之后触发
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
//获取返回的数据
var data = JSON.parse(xhr.responseText); //将后端传过来的json数据解析为对象
// console.log(data.like_nums);
if (data.add_flag) {
var thumbsSpan = document.querySelector(".thumbs-up>span");
var metaSpan = document.querySelector(".article-meta>span.like>span");
thumbsSpan.innerHTML = data.likes_nums;
metaSpan.innerText = data.likes_nums;
message.showSuccess("谢谢老铁的赞~~");
} else {
message.showInfo("兄die,您已赞过,谢谢~~");
}
}
};
请求类型GET和POST区别
- GET请求会将参数拼接在url后进行传递,而POST请求则是作为HTTP消息的实体内容发送给WEB服务器。当然在Ajax请求中,这种区别对用户是不可见的。
jquery的ajax请求
// 发送请求
$.ajax({
url: "/admin/uploadImageToServer/",
type: "POST",
data: formData,
// 定义文件的传输
processData: false, // 必须false才会避开JQ对formdata的默认处理
contentType: false, // 必须false才会自动加上正确的Content-Type
success: function (res) {
if (res["code"] === 2){
swal({
title: "图片上传成功",
text: '',
type: 'success',
showCancelButton: false,
showConfirmButton: false,
timer: 1500
});
// 先清除,再将url填充
$("#article-thumbnail-url").val();
$("#article-thumbnail-url").val(res["data"]["image_url"]);
}else{
swal({
title: res["msg"],
text: '',
type: "error",
showCancelButton: false,
showConfirmButton: false,
timer: 1500
});
}
},
error: function (err) {
swal({
title: '服务器错误,请重试!',
text: '',
type: "error",
showCancelButton: false,
showConfirmButton: false,
timer: 1500
});
}
});
前后端发送和后端接受处理区别:
1.GET方式
type: "GET",
data: {'username': username}
print(request.GET) # <QueryDict: {'username': ['admin']}>
-----------
data: JSON.stringify({'username': username})
print(request.GET) #<QueryDict: {'{"username":"admin"}': ['']}>
-----
request.body = 》 b''
2.POST方式
type: 'POST',
data: {'username': username, 'email': email, 'password': password},
print(request.body) #b'username=llp182&email=12%40qq.com&password=1q2w3e4r'
print(request.POST) # <QueryDict: {'email': ['12@qq.com'], 'username': ['llp182'], 'password': ['1q2w3e4r']}>
---
type: 'POST',
data: JSON.stringify({'username': username, 'email': email, 'password': password}),
print(request.body) #b'{"username":"llp182","email":"22@qq.com","password":"1q2w3e4r"}'
print(request.POST) #<QueryDict: {'{"username":"llp182","email":"22@qq.com","password":"1q2w3e4r"}': ['']}>
总结:
以上通过 XMLHttpRequest或者封装后的框架进行网络请求,这种方式已经有点老旧了,配置和调用方式非常混乱,近几年刚刚出来的Fetch提供了一个更好的替代方法,它不仅提供了一种简单,合乎逻辑的方式来跨网络异步获取资源,而且可以很容易地被其他技术使用。下次研究分享