向服務器發送請求的途徑:javascript
(1)瀏覽器地址欄,默認get請求css
(2)form表單:get請求、post請求html
(3)a標籤,默認get請求前端
(4)Ajax 特色:異步請求、局部刷新java
AJAX(Asynchronous Javascript And XML)翻譯成中文就是「異步Javascript和XML」。即用Javascript語言與服務器進行異步交互,傳輸的數據爲XML(固然,傳輸的數據不僅是XML,如今更多使用json數據)。python
AJAX除了異步的特色外,還有一個就是:瀏覽器頁面局部刷新;(這一特色給用戶的感覺是在不知不覺中完成請求和響應過程)jquery
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .error{ color:red } </style> </head> <body> <form class="Form"> <p>姓名 <input class="v1" type="text" name="username" mark="用戶名"></p> <p>密碼 <input class="v1" type="text" name="email" mark="郵箱"></p> <p><input type="submit" value="submit"></p> </form> <script src="jquery-3.1.1.js"></script> <script> $(".Form :submit").click(function(){ flag=true; $("Form .v1").each(function(){ var value=$(this).val(); if (value.trim().length==0){ var mark=$(this).attr("mark"); var $span=$("<span>"); $span.html(mark+"不能爲空!"); $span.prop("class","error"); $(this).after($span); setTimeout(function(){ $span.remove(); },800); flag=false; return flag; } }); return flag }); </script> </body> </html>
當咱們在百度中輸入一個「老」字後,會立刻出現一個下拉列表!列表中顯示的是包含「傳」字的4個關鍵字。ajax
其實這裏就使用了AJAX技術!當文件框發生了輸入變化時,瀏覽器會使用AJAX技術向服務器發送一個請求,查詢包含「傳」字的前10個關鍵字,而後服務器會把查詢到的結果響應給瀏覽器,最後瀏覽器把這4個關鍵字顯示在下拉列表中。chrome
場景:數據庫
當輸入用戶名後,把光標移動到其餘表單項上時,瀏覽器會使用AJAX技術向服務器發出請求,服務器會查詢名爲yuan的用戶是否存在,最終服務器返回true表示名爲yuan的用戶已經存在了,瀏覽器在獲得結果後顯示「用戶名已被註冊!」。
Ajaxdemo/urls.py:
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('test_ajax/', views.test_ajax) ]
app01/views.py:
from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return render(request, "index.html") def test_ajax(request): return HttpResponse("Hello kobe!")
templates/index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static/jquery-3.3.1.js"></script> </head> <body> <h2>this is Index!</h2> <button class="Ajax">Ajax</button> <p class="content"></p> <script> $(".Ajax").click(function () { // 發送Ajax請求 $.ajax({ url:"/test_ajax", // 請求url,不寫ip和端口,默認使用這個腳本所在的地址和端口 type:"get", // 請求方式,還有post請求 success:function (data) { // 回調函數:事件執行完,對應執行的函數 console.log(data) // 給html文本賦值 $(".content").html(data) } }) }) </script> </body> </html>
點擊Ajax按鈕後,出現以下效果:
上面是最簡單的Ajax的get請求,若是想傳遞數據:
$(".Ajax").click(function () { // 發送Ajax請求 $.ajax({ url:"/test_ajax", // 請求url,不寫ip和端口,默認使用這個腳本所在的地址和端口 type:"get", // 請求方式,還有post請求 data:{a:1,b:2}, // 發送數據 success:function (data) { // 回調函數:事件執行完,對應執行的函數 console.log(data) // 給html文本賦值 $(".content").html(data) } }) })
在視圖函數中打印傳遞的數據:
def test_ajax(request): print(request.GET) return HttpResponse("Hello kobe!")
控制檯輸出以下所示:<QueryDict: {'a': ['1'], 'b': ['2']}>
在urls.py中添加新視圖路徑:path('cal/', views.cal)
在views.py中添加新視圖函數:
def cal(request): print(request.POST) # <QueryDict: {'n1': ['12'], 'n2': ['23']}> n1 = int(request.POST.get("n1")) n2 = int(request.POST.get("n2")) ret = n1 + n2 return HttpResponse(ret)
templates/index.html:
<input type="text" id="num1">+<input type="text" id="num2">=<input type="text" id="ret"><button class="cal">計算</button> <script> // Ajax計算求值 $(".cal").click(function () { $.ajax({ url: "/cal/", //發送給服務器視圖處理運算 type: "POST", data:{ "n1": $("#num1").val(), "n2": $("#num2").val(), }, // 數據發出去後,請求結果發給success函數,success能夠決定將求完的值放在頁面中的位置 success:function (data) { console.log(data); $("#ret").val(data); } }) }) </script>
顯示效果以下所示:
用戶在表單輸入用戶名與密碼,經過Ajax提交給服務器,服務器驗證後返回響應信息,客戶端經過響應信息肯定是否登陸成功,成功,則跳轉到首頁,不然,在頁面上顯示相應的錯誤信息。
首先須要建立一個user表來進行校驗:
from django.db import models # Create your models here. # 建立一個user表來進行校驗 class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32)
執行數據庫遷移:
$ python3 manage.py makemigrations $ python3 manage.py migrate
添加以下用戶數據:
隨後在控制器添加login視圖路徑:
path('login/', views.login)
接着定義login視圖函數:
def login(request): print(request.POST) # <QueryDict: {'user': ['HQS'], 'pwd': ['123']}> user = request.POST.get("user") pwd = request.POST.get("pwd") print(User.objects.filter(name=user, pwd=pwd)) """ 在數據庫查詢失敗:<QuerySet []> 在數據庫查詢對應數據:<QuerySet [<User: User object (1)>]> """ user = User.objects.filter(name=user, pwd=pwd).first() print(user) # User object (1) res = {"user": None, "msg": None} if user: # user有值的狀況 res["user"] = user.name else: res["msg"] = "username or password wrong!" import json # 運用json把python的字典轉換爲json字符串進行傳遞 return HttpResponse(json.dumps(res)) # HttpResponse方法只能傳遞字符串
注意:res爲python的字典數據類型,須要先運用json把字段轉換爲json字符串再用HttpResponse方法進行傳遞。
最後是完成index.html頁面和jquery事件編寫:
<form action=""> 用戶名 <input type="text" id="user"> 密碼 <input type="password" id="pwd"> {# <input type="submit"> 這裏不用submit,用submit那是用form表單發送請求了,button不具備任何事件 #} <input type="button" value="submit" class="login_btn"><span class="error"></span> </form> <script> // 登陸驗證 $(".login_btn").click(function () { $.ajax({ url:"/login/", type:"POST", data:{ "user":$("#user").val(), "pwd":$("#pwd").val(), }, success:function (data) { console.log(data); // {"user": null, "msg": "username or password wrong!"} console.log(typeof data); // string,須要注意這是一個json字符串 var data = JSON.parse(data); // 反序列化 object {} console.log(data); // {user: null, msg: "username or password wrong!"} console.log(typeof data); // object if (data.user) { // 若是有值,則登陸成功 location.href="http://www.baidu.com" } else { // 若是沒有值,則登陸失敗,頁面顯示提示信息 $(".error").html(data.msg).css({"color":"red", "margin-left":"10px"}) } } }) }) </script>
注意:在使用JSON.parse(data)反序列化先後,data的值不變,可是數據類型從字符串變爲了object類型。
在登陸成功後,頁面跳轉到百度首頁;在登陸認證失敗時,頁面顯示效果以下:
######################------------data---------################ data: 當前ajax請求要攜帶的數據,是一個json的object對象,ajax方法就會默認地把它編碼成某種格式 (urlencoded:?a=1&b=2)發送給服務端;此外,ajax默認以get方式發送請求。 function testData() { $.ajax("/test",{ //此時的data是一個json形式的對象 data:{ a:1, b:2 } }); //?a=1&b=2 ######################------------processData---------################ processData:聲明當前的data數據是否進行轉碼或預處理,默認爲true,即預處理;if爲false, 那麼對data:{a:1,b:2}會調用json對象的toString()方法,即{a:1,b:2}.toString() ,最後獲得一個[object,Object]形式的結果。 ######################------------contentType---------################ contentType:默認值: "application/x-www-form-urlencoded"。發送信息至服務器時內容編碼類型。 用來指明當前請求的數據編碼格式;urlencoded:?a=1&b=2;若是想以其餘方式提交數據, 好比contentType:"application/json",即向服務器發送一個json字符串: $.ajax("/ajax_get",{ data:JSON.stringify({ a:22, b:33 }), contentType:"application/json", type:"POST", }); //{a: 22, b: 33} 注意:contentType:"application/json"一旦設定,data必須是json字符串,不能是json對象 views.py: json.loads(request.body.decode("utf8")) ######################------------traditional---------################ traditional:通常是咱們的data數據有數組時會用到 :data:{a:22,b:33,c:["x","y"]}, traditional爲false會對數據進行深層次迭代;
/* dataType: 預期服務器返回的數據類型,服務器端返回的數據會根據這個值解析後,傳遞給回調函數。 默認不須要顯性指定這個屬性,ajax會根據服務器返回的content Type來進行轉換; 好比咱們的服務器響應的content Type爲json格式,這時ajax方法就會對響應的內容 進行一個json格式的轉換,if轉換成功,咱們在success的回調函數裏就會獲得一個json格式 的對象;轉換失敗就會觸發error這個回調函數。若是咱們明確地指定目標類型,就可使用 data Type。 dataType的可用值:html|xml|json|text|script 見下dataType實例 */
示例:
from django.shortcuts import render,HttpResponse from django.views.decorators.csrf import csrf_exempt # Create your views here. import json def login(request): return render(request,'Ajax.html') def ajax_get(request): l=['alex','little alex'] dic={"name":"alex","pwd":123} #return HttpResponse(l) #元素直接轉成字符串alexlittle alex #return HttpResponse(dic) #字典的鍵直接轉成字符串namepwd return HttpResponse(json.dumps(l)) return HttpResponse(json.dumps(dic))# 傳到前端的是json字符串,要想使用,須要JSON.parse(data) //--------------------------------------------------- function testData() { $.ajax('ajax_get', { success: function (data) { console.log(data); console.log(typeof(data)); //console.log(data.name); //JSON.parse(data); //console.log(data.name); }, //dataType:"json", } )} 註解:Response Headers的content Type爲text/html,因此返回的是String;但若是咱們想要一個json對象 設定dataType:"json"便可,至關於告訴ajax方法把服務器返回的數據轉成json對象發送到前端.結果爲object 固然, return HttpResponse(json.dumps(a),content_type="application/json") 這樣就不須要設定dataType:"json"了。 content_type="application/json"和content_type="json"是同樣的!
方式1:後端將csrftoken傳到前端,發送post請求時攜帶這個值發送
$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, });
方式2:
<form> {% csrf_token %} </form><br><br><br>$.ajax({<br>...<br>data:{
獲取form中隱藏標籤的csrftoken值,加入到請求數據中傳給後端:
data: { csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val() },
方式3:cookie中存在csrftoken,將csrftoken值放到請求頭中
<script src="{% static 'js/jquery.cookie.js' %}"></script> $.ajax({ headers:{"X-CSRFToken":$.cookie('csrftoken')}, })
<h3>基於form表單的文件上傳</h3> <form action="" method="post" enctype="multipart/form-data"> 用戶名<input type="text" name="user"> 頭像 <input type="file" name="avatar"> <input type="submit"> </form>
注意:form標籤要添加屬性enctype="multipart/form-data"。enctype:用來編碼表單內容的 MIME 類型。form表單在你不寫enctype屬性時,也默認爲其添加了enctype屬性值,默認值是enctype="application/x- www-form-urlencoded".
def file_put(request): if request.method == "POST": # print(request.body) # 原始的請求體數據 # print(request.GET) # GET請求數據 print(request.POST) # POST請求數據:<QueryDict: {'user': ['yuan']}> print(request.FILES) # 上傳的文件數據:<MultiValueDict: {'avatar': [<InMemoryUploadedFile: bojie.jpg (image/jpeg)>]}> file_obj = request.FILES.get("avatar") with open(file_obj.name, "wb") as f: for line in file_obj: f.write(line) return HttpResponse("OK") return render(request, "file_put.html")
注意:必須從request.FILES中去取,才能將相應的文件取到。
能夠看到圖片上傳到程序根目錄,且使用上傳時的名稱。
這是最多見的 POST 提交數據的方式。瀏覽器的原生 <form> 表單,若是不設置 enctype
屬性,那麼最終就會以 application/x-www-form-urlencoded 方式提交數據。請求相似於下面這樣(無關的請求頭在本文中都省略掉了):
POST http://www.example.com HTTP/1.1 # 請求首行 Content-Type: application/x-www-form-urlencoded;charset=utf-8 # 請求頭 user=yuan&age=22 # 請求體
注意:只適用於上傳普通鍵值。
這也是一個常見的 POST 數據提交的方式。使用表單上傳文件時,必須讓 <form> 表單的 enctype
等於 multipart/form-data。
POST http://www.example.com HTTP/1.1 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="user" yuan ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="file"; filename="chrome.png" Content-Type: image/png PNG ... content of chrome.png ... ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
上面這個例子首先生成了一個 boundary 用於分割不一樣的字段,爲了不與正文內容重複,boundary 很長很複雜。而後 Content-Type 裏指明瞭數據是以 multipart/form-data 來編碼,本次請求的 boundary 是什麼內容。消息主體裏按照字段個數又分爲多個結構相似的部分,每部分都是以 --boundary
開始,緊接着是內容描述信息,而後是回車,最後是字段具體內容(文本或二進制)。若是傳輸的是文件,還要包含文件名和文件類型信息。消息主體最後以 --boundary--
標示結束。關於 multipart/form-data 的詳細定義,請前往 rfc1867 查看。
注意:這種方式通常用來上傳文件,各大服務端語言對它也有着良好的支持。
上面提到的這兩種 POST 數據的方式,都是瀏覽器原生支持的,並且現階段標準中原生 <form> 表單也只支持這兩種方式(經過 <form> 元素的 enctype
屬性指定,默認爲 application/x-www-form-urlencoded
。其實 enctype
還支持 text/plain
,不過用得很是少)。
application/json 這個 Content-Type 做爲響應頭並不陌生,如今愈來愈多的人把它做爲請求頭,用來告訴服務端消息主體是序列化後的 JSON 字符串。因爲 JSON 規範的流行,除了低版本 IE 以外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會趕上什麼麻煩。
JSON 格式支持比鍵值對複雜得多的結構化數據,這一點也頗有用。在須要提交的數據層次很是深時,能夠把數據 JSON 序列化後再提交的。不過須要把 JSON 字符串做爲 val,仍然放在鍵值對裏,以 x-www-form-urlencoded 方式提交。
模板層file_put.html:
<head> <script src="/static/jquery-3.3.1.js"></script> </head> <body> <h3>基於Ajax文件上傳</h3> 用戶名<input type="text" name="user"> <input type="button" class="btn" value="Ajax"> <script> $(".btn").click(function () { $.ajax({ url: "", type: "post", contentType:"application/json", // 告訴服務器編碼類型改成json數據 data: JSON.stringify({ // JSON序列化的方法 a:1, b:2 }), success: function(data){ console.log(data) } }) }) </script> </body>
注意:jquery的JSON序列化方法JSON.stringify()。
模板層:
<script> $(".btn").click(function () { $.ajax({ url: "", type: "post", //不加contentType,默認是application/x-www-form-urlencoded 方式 data: { a:1, b:2 }, success: function(data){ console.log(data) } }) }) </script>
def file_put(request): if request.method == "POST": print("body", request.body) # 請求報文的請求體 # print(request.GET) # GET請求數據 print("post", request.POST) # POST請求數據:<QueryDict: {'user': ['yuan']}> """ 只有contentType=urlencoded的時候,request.POST纔會有數據: body b'a=1&b=2' post <QueryDict: {'a': ['1'], 'b': ['2']}> contentType:"application/json" 狀況下輸出: body b'{"a":1,"b":2}' post <QueryDict: {}> """ return HttpResponse("OK") return render(request, "file_put.html")
注意:POST只有當請求是urlencoded的時候,纔會將request.body裏的內容解析成一個字典格式,方便的去獲取值。所以使用其餘格式時,須要本身去對body進行解析。
<h3>基於Ajax文件上傳</h3> 用戶名<input type="text" id="user"> 頭像 <input type="file" id="avatar"> <input type="button" class="btn" value="Ajax"> <script> // ajax上傳文件 $(".btn").click(function () { var formdata = new FormData(); // 注意構建的formdata對象 formdata.append("user", $("#user").val()); // append鍵值 formdata.append("avatar", $("#avatar")[0].files[0]); $.ajax({ url:"", type:"post", // 傳formdata數據必定要寫下面這兩個參數 contentType:false, // 在ajax這一層不作任何編碼(不設置內容類型) processData:false, // 在ajax這一層不作預處理(不處理數據) data:formdata, // 將formdata對象放在data裏面發送 success: function (data) { console.log(data); } }) }); </script>
def file_put(request): if request.method == "POST": print("body", request.body) # 請求報文的請求體 # print(request.GET) # GET請求數據 print("post", request.POST) # POST請求數據 print(request.FILES) # 上傳的文件數據 """ body b'------WebKitFormBoundary7aWZK41JdkpQEnfA\r\nContent-Disposition: form-data; name="user"\r\n\r\nyuan\r\n------WebKitFormBoundary7aWZK41JdkpQEnfA\r\nContent-Disposition: form-data; name="avatar"; filename="bojie.jpg"\r\nContent-Type: image/jpeg..... post <QueryDict: {'user': ['yuan']}> <MultiValueDict: {'avatar': [<InMemoryUploadedFile: bojie.jpg (image/jpeg)>]}> """ file_obj = request.FILES.get("avatar") with open(file_obj.name, "wb") as f: for line in file_obj: f.write(line) return HttpResponse("OK") return render(request, "file_put.html")
文件上傳完成: