一個(gè)動(dòng)態(tài)網(wǎng)站是需要前端和后端進(jìn)行數(shù)據(jù)交互出革。
什么是Ajax
Ajax是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁的技術(shù)。Ajax 不是一種新的編程語言旨枯,而是一種用于創(chuàng)建更好更快以及交互性更強(qiáng)的Web應(yīng)用程序的技術(shù)栖榨。
- AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)
- 傳統(tǒng)的網(wǎng)頁(不使用 Ajax)如果需要更新內(nèi)容,必需重載整個(gè)網(wǎng)頁面。
- AJAX 最大的優(yōu)點(diǎn)是在不重新加載整個(gè)頁面的情況下,可以與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁內(nèi)容捅彻。
ajax目的:提高用戶體驗(yàn)贤旷,較少網(wǎng)絡(luò)數(shù)據(jù)的傳輸量。
Ajax工作原理
網(wǎng)頁DOM對(duì)象可以精確地對(duì)網(wǎng)頁中的部分內(nèi)容進(jìn)行操作砾脑、XML作為單純的數(shù)據(jù)存儲(chǔ)載體使得客戶端與服務(wù)器交換的只是網(wǎng)頁內(nèi)容的數(shù)據(jù)而沒有網(wǎng)頁樣式等等的附屬信息幼驶、XMLHttpRequest是與瀏覽器本身內(nèi)置的request相互獨(dú)立的與服務(wù)器交互的請(qǐng)求對(duì)象。
Ajax使用
- 創(chuàng)建XMLHttpRequest對(duì)象,也就是創(chuàng)建一個(gè)異步調(diào)用對(duì)象韧衣。
var xhr;
if (window.XMLHttpRequest) { //檢查瀏覽器的XMLHttpRequest屬性盅藻,如果為真則支持XMLHttpRequest
// IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執(zhí)行代碼
xhr=new XMLHttpRequest();
} else {
// IE6, IE5 瀏覽器執(zhí)行代碼
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
2.向服務(wù)器發(fā)送請(qǐng)求
xhr.open(method,url,async);
send(string); //post請(qǐng)求時(shí)才使用字符串參數(shù)厢漩,否則不用帶參數(shù)辉懒。
- method:請(qǐng)求的類型抹竹,常見的get或post方法
- url:向服務(wù)器請(qǐng)求的地址
- async:true(異步)或 false(同步),默認(rèn)為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請(qǐng)求一定要設(shè)置請(qǐng)求頭的格式內(nèi)容;
2)post請(qǐng)求參數(shù)放在send里面窗轩,即請(qǐng)求體.
- 服務(wù)器響應(yīng)
ajax發(fā)起請(qǐng)求某残,django后端通過url規(guī)則進(jìn)行匹配找到對(duì)應(yīng)的視圖進(jìn)行處理,然后返回處理后的結(jié)果給后端搬素,比如上面發(fā)起的是post請(qǐng)求胯舷,對(duì)應(yīng)url在django中匹配的是article_likes
視圖函數(shù)
path(r'<int:article_id>/likes/', article_likes, name='article_likes'),
article_likes
視圖函數(shù)
def article_likes(request, article_id):
article = get_object_or_404(Article, pk=article_id)
# 判斷是否同一個(gè)IP點(diǎn)贊盈蛮,若是重復(fù)則不能繼續(xù)點(diǎn)贊,反之點(diǎn)贊數(shù)也要相加
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}
# 有就取這個(gè)數(shù)據(jù)淹接,如果沒有就創(chuàng)建數(shù)據(jù),返回元組(<Column: 關(guān)于>, 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: # 如果新創(chuàng)建了
article.increase_likes() # 點(diǎn)贊數(shù)+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后端根據(jù)前端ajax的請(qǐng)求進(jìn)行相應(yīng)處理,并返回處理結(jié)果巷屿。
關(guān)于JsonResponse
class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None,**kwargs)
這個(gè)類是HttpRespon的子類栽渴,它主要和父類的區(qū)別在于:
1.它的默認(rèn)Content-Type 被設(shè)置為: application/json;
2.第一個(gè)參數(shù),data應(yīng)該是一個(gè)字典類型礁鲁,當(dāng) safe 這個(gè)參數(shù)被設(shè)置為:False ,那data可以填入任何能被轉(zhuǎn)換為JSON格式的對(duì)象浊吏,比如list, tuple, set。 默認(rèn)的safe 參數(shù)是 True. 如果你傳入的data數(shù)據(jù)類型不是字典類型救氯,那么它就會(huì)拋出 TypeError的異常找田。
3.json_dumps_params參數(shù)是一個(gè)字典,它將調(diào)用json.dumps()方法并將字典中的參數(shù)傳入給該方法。
#如果這樣返回着憨,ajax還需要進(jìn)行json解析
#views.py
return HttpResponse(json.dumps({"msg":"ok!"}))
#index.html
var data=JSON.parse(data) //先通過JSON.parse 將 JSON 字符串轉(zhuǎn)換成對(duì)象墩衙。
console.log(data.msg);
#如果這樣返回,兩邊都不需要進(jìn)行json的序列化與反序列化甲抖,ajax接受的直接是一個(gè)對(duì)象
#views.py
from django.http import JsonResponse
return JsonResponse({"msg":"ok!"})
#index.html
console.log(data.msg);
javascript與python序列化和反序列化之間的轉(zhuǎn)換:
Javascript object {name:"xiaoming"} ==> json的轉(zhuǎn)換方式
JSON.stringify(data) ==> json.dumps
JSON.parse(data) ==> json.loads()
前端根據(jù)服務(wù)器相應(yīng)進(jìn)行相應(yīng)處理漆改。
前端數(shù)據(jù)獲取:
responseText 獲得字符串形式的響應(yīng)數(shù)據(jù)准谚。
responseXML 獲得XML 形式的響應(yīng)數(shù)據(jù)挫剑。
目前xml格式已經(jīng)用的不多,json用的比較多柱衔,可以通過將responseText轉(zhuǎn)換為對(duì)象進(jìn)行操作樊破。
分兩種情況處理,同步或異步
1.同步情況脆炎,前端發(fā)起請(qǐng)求需要等服務(wù)器后端處理完返回才能繼續(xù)運(yùn)行下個(gè)流程簇爆。
xhr.open('GET','/articles/?page='+ page);
xhr.send();
let res = JSON.parse(xhr.responseText); //object,將一個(gè) JSON 字符串轉(zhuǎn)換為對(duì)象
直接在send()后面處理返回來的數(shù)據(jù)硕勿。
2.異步情況粱栖,前端發(fā)起完請(qǐng)求就不管渣淤,可以繼續(xù)下一個(gè)流程渠退,等服務(wù)器處理完會(huì)調(diào)用荠锭。 異步處理相對(duì)比較麻煩,要在請(qǐng)求狀態(tài)改變事件中處理。
注冊(cè)回調(diào)函數(shù)onreadystatechange
,發(fā)送一個(gè)請(qǐng)求后著摔,客戶端無法確定什么時(shí)候會(huì)完成這個(gè)請(qǐng)求摹察,所以需要用事件機(jī)制來捕獲請(qǐng)求的狀態(tài)查坪,XMLHttpRequest對(duì)象提供了onreadyStateChange事件實(shí)現(xiàn)這一功能罩阵。這類似于回調(diào)函數(shù)的做法。
onreadyStateChange事件是在readyState屬性發(fā)生改變時(shí)觸發(fā)的帽驯,readyState的值表示了當(dāng)前請(qǐng)求的狀態(tài),在事件處理程序中可以根據(jù)這個(gè)值來進(jìn)行不同的處理书闸。
readyState有五種可取值
通常在事件中判斷readyState的值是在請(qǐng)求完畢時(shí)才做處理尼变,status存儲(chǔ)了服務(wù)器端返回的Http請(qǐng)求響應(yīng)代碼,它表示請(qǐng)求的處理結(jié)果浆劲。
status:
等待請(qǐng)求處理成功嫌术,然后再進(jìn)行局部刷新。
//注冊(cè)回調(diào)函數(shù)
//請(qǐng)求響應(yīng)回來之后觸發(fā)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
//獲取返回的數(shù)據(jù)
var data = JSON.parse(xhr.responseText); //將后端傳過來的json數(shù)據(jù)解析為對(duì)象
// 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牌借,您已贊過度气,謝謝~~");
}
}
};
請(qǐng)求類型GET和POST區(qū)別
- GET請(qǐng)求會(huì)將參數(shù)拼接在url后進(jìn)行傳遞,而POST請(qǐng)求則是作為HTTP消息的實(shí)體內(nèi)容發(fā)送給WEB服務(wù)器走哺。當(dāng)然在Ajax請(qǐng)求中,這種區(qū)別對(duì)用戶是不可見的哲虾。
jquery的ajax請(qǐng)求
// 發(fā)送請(qǐng)求
$.ajax({
url: "/admin/uploadImageToServer/",
type: "POST",
data: formData,
// 定義文件的傳輸
processData: false, // 必須false才會(huì)避開JQ對(duì)formdata的默認(rèn)處理
contentType: false, // 必須false才會(huì)自動(dòng)加上正確的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: '服務(wù)器錯(cuò)誤,請(qǐng)重試束凑!',
text: '',
type: "error",
showCancelButton: false,
showConfirmButton: false,
timer: 1500
});
}
});
前后端發(fā)送和后端接受處理區(qū)別:
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"}': ['']}>
總結(jié):
以上通過 XMLHttpRequest或者封裝后的框架進(jìn)行網(wǎng)絡(luò)請(qǐng)求,這種方式已經(jīng)有點(diǎn)老舊了晒旅,配置和調(diào)用方式非常混亂汪诉,近幾年剛剛出來的Fetch提供了一個(gè)更好的替代方法废恋,它不僅提供了一種簡(jiǎn)單,合乎邏輯的方式來跨網(wǎng)絡(luò)異步獲取資源扒寄,而且可以很容易地被其他技術(shù)使用鱼鼓。下次研究分享