這里將自己這段時間學習的關於前后台數據交互的筆記寫在這里,這里包含了Django傳輸數據給JS,AJAX的相關問題,跨域問題,如何解決AJAX的跨域問題等等。比較凌亂,請看到這篇博客的盆友見諒,如果我將最近學習的這段內容理清楚了,我會再寫一篇易於理解的文章做以鞏固。
有時候我們想把一個list或者dict等JSON對象傳到網頁的JavaScript,用JS進行處理,比如用JS將數據可視化顯示到網頁上,這里說兩種:
1,直接在視圖函數中渲染一個list或者dict的內容,和網頁其他部分一起顯示到網頁(一次性的渲染,而且是同一次請求)
2,頁面加載完成后,在頁面操作,在頁面上通過AJAX方法得到新的數據(再向服務器發送一次請求)並顯示在網頁上,在這種情況適用於頁面不刷新的情況下,動態加載一些內容。比如用戶輸入一個值或者點擊某個地方,動態的把相應內容顯示在網頁上。
方法一:Django傳遞數據給JS
這個例子是把一個list傳遞給JavaScript,然后經過處理后顯示到網頁上,比如可能需要JS進行可視化數據。
1 ADMIN/urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include urlpatterns = [ path('admin/', admin.site.urls), path('user12/', include('user12.urls')), ]
2 user12/urls.py
from django.urls import path from user12 import views urlpatterns = [ path('login/', views.login) ]
3 user12/views.py
from django.shortcuts import render import json # Create your views here. def login(request): obj = {"name": "james"} return render(request, 'user12/index.html', {'objs':json.dumps(obj)})
views.py中返回的函數值要用json.dumps(xx)處理,參數xx需要是字典或者列表(只要JSON與Python序列化的數據類型可轉化即可)
4 template/user12/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var temp = {{ objs|safe }} alert(temp.name); alert(temp['name']) </script> </body> </html>
有時候我們需要在不刷新的情況下載入一些內容,所以下面我們學習ajax技術。
AJAX介紹
Asynchronous JavaScript and XML (異步的JavaScript和XML),他不是某種編程語言,而是一種在無需刷新整個網頁的情況下能夠更新部分網頁的技術。
Ajax是使用JavaScript技術向服務器發送異步請求,其實他是一種js技術。
1,Ajax的特點
Ajax 有兩大特性,也是它的優點。
1.1,異步交互
客戶端發出一個請求后,無需等待服務器響應結束,就可以發出第二個請求
1.2,局部刷新
這一特點給用戶的感受就是在不知不覺中完成請求和響應
局部刷新示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript"> window.onload = function() {//當文檔加載完畢時執行本函數 var form = document.getElementById("form1");//獲取表單元素對象 form.onsubmit = function() {//給表單元素添加一個監聽,監聽表單被提交事件 var usernameValue = form.username.value;//獲取表單中名為username的表單元素值 if(!usernameValue) {//判斷該值是否為空 var usernameSpan = document.getElementById("usernameSpan");//得到usernmae元素后的<span>元素 usernameSpan.innerText = "用戶名不能為空!";//設置span元素內容! return false;//返回false,表示攔截了表單提交動作 } return true;//不攔截表單提交動作 }; }; </script> </head> <body> <h1>注冊頁面</h1> <form action="" method="post" id="form1"> 用戶名:<input type="text" name="username"> <span id="usernameSpan"></span> <br/>密碼:<input type="password" name="password"> <span id="passowrdSpan"></span> <br/> <input type="submit" value="注冊"> </form> </body> </html>
界面如下:
效果界面如下:
2,ajax的應用
舉個例子,網站的輸入界面,當輸入關鍵詞的時候,會彈出你想輸入的東西,如下:
當我們在百度輸入“python”后,會立馬出現一個下拉列表! 列表中顯示的是包含“Python”字的四個關鍵字。其實這就使用了AJAX技術,當文本框發生了輸入變化時,瀏覽器會使用AJAX技術向服務器發送一個請求,查詢包含“python”字的前10個關鍵字,然后服務器會把查詢到的結果響應給瀏覽器,最后瀏覽器把這四個關鍵字顯示在下拉列表中。
- 整個過程中頁面沒有刷新,知識刷新頁面的局部位置而已!
- 當請求發送后,瀏覽器還可以進行其他操作,無需等待服務器的響應!
3,Ajax的優缺點
3.1 優點:
- AJAX使用Javascript技術向服務器發送異步請求;
- AJAX無須刷新整個頁面;
- 因為服務器響應內容不再是整個頁面,而是頁面中的局部,所以AJAX性能高;
3.2 缺點:
- AJAX並不適合所有場景,很多時候還是要使用同步交互;
- AJAX雖然提高了用戶體驗,但無形中向服務器發送的請求次數增多了,導致服務器壓力增大;
- 因為AJAX是在瀏覽器中使用Javascript技術完成的,所以還需要處理瀏覽器兼容性問題;
4,使用jQuery展示Ajax示例
Ajax是使用JavaScript技術向服務器發送異步請求,其實他是一種js技術,接下來我們使用更簡潔的JQuery寫兩個ajax的例子,看看它的工作原理。
4.1:Ajax發送簡單數據類型
在這里我們僅發送一個簡單的字符串。
4.1.1 html代碼:template/user12/ajax1.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" onclick="AjaxSubmit();" value="提交"> <script> function AjaxSubmit() { var host = '127.0.0.1'; var port = '8080'; $.ajax({ url:'/user12/ajax_submit/', type:'POST', data:{host:host, port:port}, success:function (arg){ } }) } </script> </body> <script src="/static/jquery-3.3.1.min.js"></script> </html>
上面的代碼意思是:Ajax 發送請求給server端,server端接收並用對應的視圖函數處理,且返回值給AJAX請求,AJAX請求的success就是請求成功后的回調函數,參數data就是server端的返回值。
4.1.2 視圖函數:user12/views.py
from django.shortcuts import render import json # Create your views here. def ajax_submit(request): # 客戶端發來的數據 print(request.POST) return render(request, 'user12/ajax1.html')
4.1.3 APP 下urls函數: user12/urls.py
from django.urls import path from user12 import views urlpatterns = [ path('ajax_submit/', views.ajax_submit), ]
4.1.4 打印出來的數據樣式:
4.2:Ajax發送復雜的數據類型
在這里我們僅發送一個列表中包含字典數據類型。
由於發送的數據類型是列表 字典的格式,我們提前要把他們轉換成字符串形式,否則后台程序接收到的數據格式不是我們想要的類型,所以在ajax傳輸數據時需要JSON。
4.2.1 html代碼:template/user12/ajax1.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" onclick="AjaxSubmit_set();" value="提交集合"> <script src="/static/jquery-3.3.1.min.js"></script> <script> function AjaxSubmit_set() { var data_list = [ {'name':'james','age':34}, {'name':'durant','age':31}, {'name':'curry','age':30}, ]; $.ajax({ url:'/user13/ajax_submit_set/', type:'POST', tradition:true, data:{data:JSON.stringify(data_list)}, success: function (arg) { } }) } </script> </body> </html>
4.2.2 視圖函數:user12/views.py
from django.shortcuts import render # Create your views here. def ajax_submit_set(request): # 客戶端發送過來的數據 print(request.POST) return render(request, 'user13/ajax1.html')
4.2.3 APP 下urls函數: user12/urls.py
from django.urls import path from user13 import views urlpatterns = [ path('ajax_submit_set/', views.ajax_submit_set), ]
4.2.4 打印出來的數據樣式:
4.2.5 html 的部分代碼解析
success:function(arg) {}
如果ajax提交數據成功,那么就會自動執行這里的函數。
5, JS實現Ajax與后台交互(*****)
5.1 JS實現ajax的四步操作:
- 創建核心對象
- 使用核心對象打開與服務器的連接
- 發送請求
- 注冊監聽:監聽服務器響應
其實AJAX就是在JavaScript中添加了一個對象:XMLHttpRequest對象。所有的異步交互都是使用XMLHttpRequest對象完成的。也就是說,我們只需要學習一個JavaScript的新對象即可。
var xmlHttp = new XMLHttpRequest();(大多數瀏覽器都支持DOM2規范)
5.2 XMLHTTPRequest 方法
- open(請求方式, URL, 是否異步)
- send(請求體)
- onreadystatechange,指定監聽函數,它會在xmlHttp對象的狀態發生變化時被調用
- readyState,當前xmlHttp對象的狀態,其中4狀態表示服務器響應結束
- status:服務器響應的狀態碼,只有服務器響應結束時才有這個東東,200表示響應成功;
- responseText:獲取服務器的響應體
注意:各個瀏覽器對XMLHttpRequest的支持也是不同的!為了處理瀏覽器兼容問題,給出了下面方法來創建XMLHttpRequest 對象。
function createXMLHttpRequest() { var xmlHttp; // 適用於大多數瀏覽器,以及IE7和IE更高版本 try{ xmlHttp = new XMLHttpRequest(); } catch (e) { // 適用於IE6 try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { // 適用於IE5.5,以及IE更早版本 try{ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e){} } } return xmlHttp; }
5.3 使用流程
5.3.1 打開與服務器的連接(open方法)
當得到XMLHttpRequest對象后,就可以調用該對象的open()方法打開與服務器的連接了。
open()方法的參數如下:
open(method, url, async): method:請求方式,通常為GET或POST; url:請求的服務器地址,例如:/ajaxdemo1/AServlet,若為GET請求,還可以在URL后追加參數; async:這個參數可以不給,默認值為true,表示異步請求; var xmlHttp = createXMLHttpRequest(); xmlHttp.open("GET", "/ajax_get/", true);
5.3.2 發送請求
當使用open打開連接后,就可以調用XMLHttpRequest對象的send() 方法發送請求了。send()方法的參數為POST請求參數,即對應HTTP協議的請求體內容,若是GET請求,需要在URL后連接參數。
注意:若沒有參數,需要給出 null 為參數!若不給出 null 為參數,可能會導致FireFox瀏覽器不能正常發送請求!
xmlHttp.send(null)
HTTP請求
HTTP 是計算機通過網絡進行通信的規則 HTTP是一種無狀態的協議,服務端不保存連接的信息。 一個完整的Http請求過程,一般有以下七個步驟: 1,建立TCP連接 2,Web瀏覽器向Web服務器發送請求命令 3,Web瀏覽器發送請求頭信息 4,Web服務器應答 5,Web服務器發送應答頭信息 6,Web服務器向瀏覽器發送數據 7,Web服務器關閉TCP連接
5.3.3 接受服務器響應
當請求發送出去后,服務器端Servlet 就開始執行了,但是服務器端的響應還沒有接收到。接下來我們來接收服務器的響應。
XMLHttpRequest對象有一個onreadystatechange事件,它會在XMLHttpRequest對象的狀態發生變化時被調用。下面介紹一下XMLHttpRequest對象的5種狀態:
- 0:初始化未完成狀態,只是創建了XMLHttpRequest對象,還未調用open()方法;
- 1:請求已開始,open()方法已調用,但還沒調用send()方法;
- 2:請求發送完成狀態,send()方法已調用;
- 3:開始讀取服務器響應;
- 4:讀取服務器響應結束。
onreadystatechange事件會在狀態為1,2,3,4時引發。
下面代碼會被執行四次! 對應的XMLHTTPResponse的四種狀態!
xmlHttp.onreadystatechange = function() { alert('hello'); };
但是我們通常只關心最后一種狀態,即讀取服務器響應結束時,客戶端才會做出改變。我們可以通過XMLHttpRequest對象的readyState 屬性來得到XMLHttpRequest對象的狀態。
xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4) { alert('hello'); } };
其實我們還要關心服務器響應的狀態碼是否是200,其服務器響應為404,或者500,那么就表示請求失敗了。我們可以通過XMLHTTPResponse對象的status屬性得到服務器的狀態碼。
最后,我們還需要獲取得到服務器響應的內容,可以通過XMLHTTPResponse對象的responseText得到服務器響應內容。
xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { alert(xmlHttp.responseText); } };
5.3.4,if 發送post請求
1,需要設置請求頭:
xmlHttp.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
注意:form表單會默認這個鍵值對不設定,Web服務器會忽略請求體的內容
2,在發送的時候就可以指定請求體了
xmlHttp.send(“username=james&password=123”)
5.3.5,contentType類型
1,contentType類型一
下面將參數的默認使用方式總結如下:
data: 當前ajax請求要攜帶的數據,是一個object對象,ajax方法就會默認地把 它編碼成某種格式(urlencoded:?a=1&b=2)發送給服務端;此外,ajax默認以get方 式發送請求。 contentType:"application/x-www-form-urlencoded"。發送信息至服務器時內容 編碼類型。用來指明當前請求的數據編碼格式;urlencoded:?a=1&b=2;
2,contentType類型二
上述這種默認參數形式,data中的csrf跨站請求偽造鍵值對會被中間件自動識別,contentType參數還有如下一種形式,介紹如下:
contentType:"application/json",即向服務器發送一個json字符串。 注意:contentType:"application/json"一旦設定,data必須是json字符串,不能是json對象
這種類型,使用request.POST 無法顯示,這種類型要使用 request.body才能顯示數據。
5.3.6 AJAX實現小結
創建XMLHttpRequest對象; 調用open()方法打開與服務器的連接; 調用send()方法發送請求; 為XMLHttpRequest對象指定onreadystatechange事件函數,這個函數會在 XMLHttpRequest的1、2、3、4,四種狀態時被調用; XMLHttpRequest對象的5種狀態,通常我們只關心4狀態。 XMLHttpRequest對象的status屬性表示服務器狀態碼,它只有在readyState為 4時才能獲取到。 XMLHttpRequest對象的responseText屬性表示服務器響應內容,它只有在 readyState為4時才能獲取到!
6,Ajax前后台數據傳輸
jQuery底層AJAX實現,簡單易用的高層實現$.get ,$.post等,后端返回的數據會被當做ajax的success回調函數中的data參數,回調函數success的status的成功時返回值如果打印出來是success,獲取值失敗的時候什么都做不出來。
6.1示例:get方式傳輸JSON數據
js代碼,從后台獲取info信息
$.ajax({ url:'/login/', dataType:'json', success:function(data){ alert(data['info']); } })
views.py ,將JSON數據傳送給前端
from django.http import JsonResponse def login(request): if request.is_ajax(): response = JsonResponse({"info":"驗證碼發送成功"}) return response
此例傳輸的是文本數據,和json數據差不多,只是在js里面數據類型改成text,視圖函數里面Jsonresponse換成httpresponse。
js代碼
$.ajax({ url: '/login/', dataType: 'text', success: function (data) { console.log(data) } })
views.py
from django.http import HttpResponse def login(request): if request.is_ajax(): response = HttpResponse("驗證碼發送成功") return response
6.2示例:post傳輸JSON數據
js代碼,post請求方式給后端,傳數據的時候要以字典的形式發送
var host = '127.0.0.1'; var port = '8080'; $.ajax({ url:'/user12/ajax_submit/', type:'POST', data:{host:host, port:port}, success:function (arg){ alert(data['host']) } })
views.py
from django.http import JsonResponse def login(request): if request.is_ajax(): # 直接獲取所有的post請求數據 data = request.POST # 獲取其中的某個鍵的值 host = request.POST.get("host") print(data) print(host) # 將前端傳來的數據再次傳回前端,只是為了測試 response = JsonResponse({'host':host}) return response
6.3 get() 和 post()方式
//get()方式 $.ajax({ url:'./data/index.txt', type:'get', dataType:'text', success:function(data){ $('p').html(data); }, error:function(error){ console.log(error) } //post()方式 $.ajax({ url:'/index', type:'post', data:{name:'張三',age:12}, success:function(data){ $('p').html(data); }, error:function(error){ console.log(error) }
7,Ajax實例:登錄驗證頁面
7.1 功能介紹
在注冊表單中,當用戶填寫了用戶名后,把光標移開后,會自動向服務器發送異步請求。服務器返回true或false,返回true表示這個用戶名已經被注冊過,返回false表示沒有注冊過。
客戶端得到服務器返回的結果后,確定是否在用戶名文本框后顯示“用戶名已被注冊”的錯誤信息!
7.2 案例分析
- 頁面中給出注冊表單
- 在username表單字段中添加onblur事件,調用send()方法
- send() 方法獲取username表單字段的內容,向服務器發送異步請求,參數為username
- django的視圖函數:獲取username參數,判斷是否為“james”,如果是響應True,否則響應False
7.3 代碼示例
views.py
from django.shortcuts import render, HttpResponse # Create your views here. from django.views.decorators.csrf import csrf_exempt def login(request): print('hello ajax login ') return render(request, 'user11_ajax/login.html') @csrf_exempt def ajax_check(request): print("ajax check ok") username = request.POST.get('username', None) if username == 'james': print('True') return HttpResponse("True") print("False") return HttpResponse("False")
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <script type="text/javascript"> function createXMLHttpRequest() { try { return new XMLHttpRequest(); } catch (e) { try { return new ActiveXObject("Msxm12.XMLHTTP"); }catch (e) { return new ActiveXObject("Mircrosoft.XMLHTTP"); } } } function send() { var xmlHttp = createXMLHttpRequest(); xmlHttp.onreadystatechange = function () { if(xmlHttp.readyState == 4 && xmlHttp.status == 200){ if(xmlHttp.responseText == 'true'){ document.getElementById('error').innerText = '用戶名以及被注冊!'; document.getElementById('error').innerText = '用戶名已經被注冊!'; }else { document.getElementById('error').innerText = "" ; document.getElementById('error').textContent = ''; } } }; xmlHttp.open("POST", '/user11_ajax/ajax_check/', true, 'json'); xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var username = document.getElementById("username").value; xmlHttp.send("username=" + username); } </script> <body> <h1> 注冊</h1> <form action="" method="post"> {% csrf_token %} <p> 用戶名:<input id="username" type="text" name="username" onblur="send()"><span id="error"></span> </p> <p> 密碼:<input type="password" name="password"> </p> <p> <input type="submit" value="submit" > </p> </form> </body> </html>
8,jQuery實現AJAX
8.1 快捷API
<1>$.get(url, [data], [callback], [type]) <2>$.post(url, [data], [callback], [type]) //type: text|html|json|script 應用: //請求參數應該盡量放在data參數中,因為可以自動編碼,手動拼接url要注意編碼問題 function testWithDataAndCallback() { //$.post... $.get('/user/list', {type: 1}, function (data, callbacktype, jqXHR) { console.log(data);//將json字符串解析成json對象 }); } -------------- <3>$.getScript()使用 AJAX 請求,獲取和運行 JavaScript: 應用: function testGetScript() { // alert(testFun(3, 4)); $.getScript('test.js', function () { alert(add(1, 6)); }); } // test.js function add(a,b){ return a+b } <4>$.getJSON() 與$.get()是一樣的,只不過就是做后一個參數type必須是json數據了。 一般同域操作用$.get()就可以,$.getJson 最主要是用來進行jsonp跨域操作的。
8.2 核心API的基本使用
<1> $.ajax的兩種寫法: $.ajax("url",{}) $.ajax({}) <2> $.ajax的基本使用 $.ajax({ url:"//", data:{a:1,b:2}, type:"GET", success:function(){} }) <3> 回調函數 $.ajax('/user/allusers', { success: function (data) { console.log(arguments); }, error: function (jqXHR, textStatus, err) { // jqXHR: jQuery增強的xhr // textStatus: 請求完成狀態 // err: 底層通過throw拋出的異常對象,值與錯誤類型有關 console.log(arguments); }, complete: function (jqXHR, textStatus) { // jqXHR: jQuery增強的xhr // textStatus: 請求完成狀態 success | error console.log('statusCode: %d, statusText: %s', jqXHR.status, jqXHR.statusText); console.log('textStatus: %s', textStatus); }, statusCode: { '403': function (jqXHR, textStatus, err) { console.log(arguments); //注意:后端模擬errror方式:HttpResponse.status_code=500 }, '400': function () { } } });
8.3 核心API的重要字段
$.Ajax的參數
<1> ----------請求數據相關: data, processData, contentType, traditional-------------- 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:聲明當前的data數據是否進行轉碼或預處理,默認為true,即預處理;if為false, 那么對data:{a:1,b:2}會調用json對象的toString()方法,即{a:1,b:2}.toString(),最后得 到一個[object,Object]形式的結果。 {"1":"111","2":"222","3":"333"}.toString(); [object Object] 該屬性的意義在於,當data是一個dom結構或者xml數據時,我們希望數據 不要進行處理,直接發過去,就可以講其設為true。 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對象 traditional:一般是我們的data數據有數組時會用到 :data:{a:22,b:33,c:["x","y"]}, traditional為false會對數據進行深層次迭代; <2> ------------------------ 響應數據: dataType、dataFilter------------------------ dataType:預期服務器返回的數據類型,服務器端返回的數據會根據這個值解析后,傳遞給回調 函數。默認不需要顯性指定這個屬性,ajax會根據服務器返回的content Type來進行轉換;如我 們的服務器響應的content Type為json格式,這時ajax方法就會對響應的內容進行一個json格式 的轉換,if轉換成功,我們在success的回調函數里就會得到一個json格式的對象;轉換失敗就會 觸發error這個回調函數。如果我們明確地指定目標類型,就可以使用data Type。 dataType的可用值:html|xml|json|text|script 見下dataType實例 dataFilter: 類型:Function 給 Ajax返回的原始數據的進行預理的函數。見下dataFilter實例 <3> 請求類型 type: 類型:String 默認值: "GET")。請求方式 ("POST" 或 "GET"), 默認為 "GET"。 注意:其它 HTTP 請求方法, 如 PUT 和 DELETE 也可以使用,但僅部分瀏覽器支持。 <4> 前置處理 beforeSend(XHR) 類型:Function 發送請求前可修改 XMLHttpRequest 對象的函數,如添加自定義 HTTP 頭。XMLHttpRequest 對象是唯一的參數。這是一個 Ajax 事件。如果返回 false 可以取消本次 ajax 請求。 見下beforeSend實例 <5> jsonp 類型:String 在一個 jsonp 請求中重寫回調函數的名字。這個值用來替代在 "callback=?" 這種 GET 或 POST 請求中 URL 參數里的 "callback" 部分,比如 {jsonp:'onJsonPLoad'} 會導致將 "onJsonPLoad=?" 傳給服務器。 <6> jsonpCallback 類型:String 為 jsonp 請求指定一個回調函數名。這個值將用來取代 jQuery 自動生成的隨機函數名。 這主要用來讓 jQuery 生 成度獨特的函數名,這樣管理請求更容易,也能方便地提供回調函 數和錯誤處理。你也可以在想讓瀏覽器緩存 GET 請求的時候,指定這個回調函數名。
8.4 實例代碼
8.4.1 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":"james","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"是一樣的! dataType
8.4.2 dataFilter實例
function testData() { $.ajax('ajax_get', { success: function (data) { console.log(data); }, dataType: 'json', dataFilter: function(data, type) { console.log(data);//["james", "little james"] console.log(type);//json //var tmp = JSON.parse(data); return tmp.length;//2 } });} dataFilter實例
8.4.3 beforeSend實例
function testData() { $.ajax('ajax_get', { beforeSend: function (jqXHR, settings) { console.log(arguments); console.log('beforeSend'); jqXHR.setRequestHeader('test', 'haha'); jqXHR.testData = {a: 1, b: 2}; }, success: function (data) { console.log(data); }, complete: function (xhr) { console.log(xhr); console.log(xhr.testData); }, })}; beforeSend實例
8.5 csrf跨站請求偽造
$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, });
9,同源策略與跨域請求
9.1什么叫同源?
URL由協議,域名,端口和路徑組成,如果兩個URL的協議,域名和端口相同,則表示他們同源。相反,只要協議,域名,端口有任何一個的不同,就當被當做的跨域。
舉個例子,對於http://store.company.com/dir/page.html進行同源檢測:
9.2 同源策略機制 Same-Origin-Policy(SOP)
瀏覽器有一個很重要的概念——同源策略(Same-Origin-Policy)。所謂同源是指,域名,協議,端口相同。不同源的客戶端腳本(JavaScript, ActionScript)在沒有明確授權的情況下,不能讀寫對方的資源。
同源策略是一種約定,它是瀏覽器最核心也是最基本的安全功能,如果缺失了同源策略,則瀏覽器的正常功能可能都會受到影響,可以說Web是構建在同源策略基礎之上的。
同源策略是瀏覽器的一個安全功能,不同源的客戶端腳本在沒有明確授權的情況下,不能讀寫對方資料。所以百度下的js腳本采用ajax讀取京東里面的文件數據是會被拒絕的。
瀏覽器采用同源策略,禁止頁面加載或者執行與自身來源不同的域的任何腳本。換句話說瀏覽器禁止的是來自不同源的“document”或者腳本,對當前“document”讀取或者設置某些屬性。
情景:
如果Web世界沒有同源策略,當你登錄淘寶賬號並打開另一個站點時,這個站點上的JavaScript 可以跨域讀取你的淘寶賬號數據,這樣整個Web世界就無隱私可言了。
比如一個惡意網站的頁面通過iframe嵌入了銀行的登錄頁面(二者不同源),如果沒有同源限制,惡意網站上的JavaScript腳本就可以在用戶登錄銀行的時候獲取用戶名和密碼。
9.3 瀏覽器中有哪些不受同源限制呢?
頁面中的鏈接,重定向以及表單提交是不會受到同源策略限制的。
跨域資源的引入是可以的,但是js不能讀寫加載的內容,如<script>、<img>、<iframe>、<link>這些包含 src 屬性的標簽可以加載跨域資源。但瀏覽器限制了JavaScript的權限使其不能讀、寫加載的內容。
9.4 跨域
跨域是指從一個域的網頁去請求另一個域的資源。比如從http://www.baidu.com/ 頁面去請求 http://www.google.com 的資源。
一個域名地址的組成
協議: http:// 子域名:www. 主域名:abc.com 端口號:8080 請求資源地址:script/jquery.js
當協議,子域名,主域名,端口號中任意一個不相同時,都算作不同域。不同域之間相互請求資源,就算做跨域。JavaScript處於安全方面的考慮,不允許跨域調用其他頁面的對象。
9.5 處理跨域的方法
1,代理
通過在同域名的Web服務器端創建一個代理
2,JSONP
JSONP 只支持GET請求
3,XHR2
HTML5 提供的XMLHttpRequest Level2:支持跨域訪問(IE10以下不支持)
說到AJAX就會不可避免的面臨兩個問題,第一個是AJAX以何種格式來交換數據?第二個是跨域的需求如何解決?這兩個問題目前都有不同的解決方案,比如數據可以用自定義字符串或者用XML來描述,跨域可以通過服務器端代理來解決。但到目前為止最被推崇或者說首選的方案還是用JSON來傳數據,靠JSONP來跨域。
JSON和JSONP雖然只有一個字母的差別,但其實他們根本不是一回事兒:JSON是一種數據交換格式,而JSONP是一種依靠開發人員的聰明才智創造出的一種非官方跨域數據交互協議。我們拿最近比較火的諜戰片來打個比方,JSON是地下黨們用來書寫和交換情報的“暗號”,而JSONP則是把用暗號書寫的情報傳遞給自己同志時使用的接頭方式。看到沒?一個是描述信息的格式,一個是信息傳遞雙方約定的方法。
10,跨域技術——JSONP
JSONP是JSON with Padding的略稱。可以讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。jsonp:是 JSON + Padding,json填充。
jsonp是json用來跨域的一個東西,原理是通過script標簽的跨域特性來繞過同源策略。它是一個非官方的協議,它允許在服務器端集成Script tags返回至客戶端,通過JavaScript callback的形式實現跨域訪問(這僅僅是JSONP簡單的實現形式)。
10.1,JSONP是怎么產生的?
- 一個眾所周知的問題,Ajax直接請求普通文件存在跨域無權限訪問的問題,不管你是靜態頁面,動態頁面,web服務,WCF,只要是跨域請求,一律不准。
- 但是,Web頁面上調用js文件時則不受是否跨域的請求(不僅如此,我們還發現凡是擁有“src”這個屬性的標簽都擁有跨域的能力,比如<script> <img> <iframe>)
- 於是我們可以判斷,當前階段如果想通過純web端(Active X 空間,服務端代理,屬於未來的HTML5之Websocket等方式不算)跨域訪問數據就只有一種可能,那就是在遠程服務器上設法把數據裝進js格式的文件里,供客戶端調用和進一步處理;
- 恰巧我們已經知道有一種叫做JSON的純字符數據格式可以簡潔的描述復雜數據,更妙的是JSON還被js原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數據;
- 這樣子解決方案就呼之欲出了,web客戶端通過與調用腳本一模一樣的方式,來調用跨域服務器上動態生成的js格式文件(一般以JSON為后綴),顯而易見,服務器之所以要動態生成JSON文件,目的就在於把客戶端需要的數據裝入進去。
- 客戶端在對JSON文件調用成功之后,也就獲得了自己所需的數據,剩下的就是按照自己需求進行處理和展現了,這種獲取遠程數據的方式看起來非常像AJAX,但其實並不一樣。
- 為了便於客戶端使用數據,逐漸形成了一種非正式傳輸協議,人們把它稱作JSONP,該協議的一個要點就是允許用戶傳遞一個callback參數給服務端,然后服務端返回數據時會將這個callback參數作為函數名來包裹住JSON數據,這樣客戶端就可以隨意定制自己的函數來自動處理返回數據了。
10.2,jsonp的js實現
JSONP 是JSON with padding 的略稱,可以讓網頁從別的域名(網站)獲取資料,即跨域讀取數據。它是一個非官方的協議,它允許在服務器端集成Script tags返回至客戶端,通過JavaScript callback 的形式實現跨域訪問(這僅僅是JSONP 簡單的實現形式)。
實例:
#---------------------------http://127.0.0.1:8001/login def login(request): print('hello ajax') return render(request,'index.html') #---------------------------返回用戶的index.html <h1>發送JSONP數據</h1> <script> function fun1(arg){ alert("hello"+arg) } </script> <script src="http://127.0.0.1:8002/get_byjsonp/"></script> //返回:<script>fun1("james")</script> #-----------------------------http://127.0.0.1:8002/get_byjsonp def get_byjsonp(req): print('8002...') return HttpResponse('fun1("james")')
這其實就是JSONP的簡單實現模式,或者說是JSONP的原型:創建一個回調函數,然后在遠程服務上調用這個函數並且將JSONP數據形式作為參數傳遞,完成回調。
將JSON數據填充進回調函數,這應該就是JSONP的JSON + Padding 的含義吧。
一般情況下,我們希望這個script標簽能夠動態的調用,而不是像上面因為固定在html里面,所以沒等頁面顯示就執行了,很不靈活。我們可以通過JavaScript動態的創建script標簽,這樣我們就可以靈活調用遠程服務了。
<button onclick="f()">submit</button> <script> function addScriptTag(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); document.body.removeChild(script); } function fun1(arg){ alert("hello"+arg) } function f(){ addScriptTag("http://127.0.0.1:8002/get_byjsonp/") } </script>
為了更加靈活,現在將你自己在客戶端定義的回調函數的函數名傳送給服務端,服務端則會返回以你定義的回調函數名的方法,將獲取的json數據傳入這個方法完成回調:
<button onclick="f()">submit</button> <script> function addScriptTag(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); document.body.removeChild(script); } function SayHi(arg){ alert("Hello "+arg) } function f(){ addScriptTag("http://127.0.0.1:8002/get_byjsonp/?callbacks=SayHi") } </script> ----------------------views.py def get_byjsonp(req): func=req.GET.get("callbacks") return HttpResponse("%s('james')"%func)
10.4 jQuery對jsonp的實現
jQuery框架也當然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法。
<script type="text/javascript"> $.getJSON("http://127.0.0.1:8002/get_byjsonp?callback=?",function(arg){ alert("hello"+arg) }); </script>
結果是一樣的,要注意的是在url的后面必須添加一個callback參數,這樣getJSON方法才會知道是用JSONP方式去訪問服務,callback后面的那個問號是內部自動生成的一個回調函數名。
此外,如果說我們想指定自己的回調函數名,或者說服務上規定了固定回調函數名該怎么辦呢?我們可以使用$.ajax方法來實現。
<script type="text/javascript" src="/static/jquery-2.2.3.js"></script> <script type="text/javascript"> $.ajax({ url:"http://127.0.0.1:8002/get_byjsonp", dataType:"jsonp", jsonp: 'callbacks', jsonpCallback:"SayHi" }); function SayHi(arg){ alert(arg); } </script> #--------------------------------- http://127.0.0.1:8002/get_byjsonp def get_byjsonp(req): callback=req.GET.get('callbacks') print(callback) return HttpResponse('%s("james")'%callback)
當然最簡單的形式還是通過回調函數來處理:
<script type="text/javascript" src="/static/jquery-2.2.3.js"></script> <script type="text/javascript"> $.ajax({ url:"http://127.0.0.1:8002/get_byjsonp", dataType:"jsonp", //必須有,告訴server,這次訪問要的是一個jsonp的結果。 jsonp: 'callbacks', //jQuery幫助隨機生成的:callbacks="wner" success:function(data){ alert(data) } }); </script> #-------------------------------------http://127.0.0.1:8002/get_byjsonp def get_byjsonp(req): callbacks=req.GET.get('callbacks') print(callbacks) #wner return HttpResponse("%s('james')"%callbacks)
jsonp: 'callbacks'就是定義一個存放回調函數的鍵,jsonpCallback是前端定義好的回調函數方法名'SayHi',server端接受callback鍵對應值后就可以在其中填充數據打包返回了;
jsonpCallback參數可以不定義,jquery會自動定義一個隨機名發過去,那前端就得用回調函數來處理對應數據了。
利用jQuery可以很方便的實現JSONP來進行跨域訪問。
注解1: JSONP一定是GET請求
注解2:
<button onclick="f()">submit</button> <script src="/static/jquery-1.8.2.min.js"></script> <script type="text/javascript"> function f(){ $.ajax({ url:"http://127.0.0.1:8002/get_byjsonp", dataType:"jsonp", jsonp: 'callbacks', success :function(data){ //傳過來的數據會被轉換成js對象 console.log(data); //Object {name: Array[2]} console.log(typeof data); //object console.log(data.name) //["james", "durant"] } }); } </script> ---------------------------------------------views.py def get_byjsonp(req): func=req.GET.get("callbacks") a=json.dumps({'name':('james','durant')}) return HttpResponse("%s(%s)"%(func,a)) #return HttpResponse("%s({'name':('james','durant')})"%func) #return HttpResponse("%s('hello')"%func) #return HttpResponse("%s([12,34])"%func) #return HttpResponse("%s(5)"%func)
補充——is_ajax:
#views.py 中可以用 request.is_ajax() 方法判斷是否是 ajax 請求,需要添加一個 HTTP 請求頭: #原生javascript: #xmlhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest"); #用 jQuery: #用 $.ajax 方法代替 $.get,因為 $.get 在 IE 中不會發送 ajax header #注意:is_ajax()在跨域ajax請求時不好使 is_ajax()
11,jQuery的各種方法概述
11.1,jQuery的load()方法
jQuery load()方法是簡單但強大的AJAX方法。
load()方法從服務器加載數據,並把返回的數據放入被選元素中。
語法:
$("selector").load(url,data,callback); 必須的url參數規定記載的url地址 可選的data參數規定與請求一同發送的查詢字符串鍵/值對的集合 可選的callback參數是load()方法完成后所執行的函數名稱 1、 $('#btn').click(function(){ //只傳一個url,表示在id為#new-projects的元素里加載index.html $('#new-projects').load('./index.html'); }) 2、 $('#btn').click(function(){ //只傳一個url,導入的index.html文件含有多個傳遞參數,類似於:index/html?name='張三' $('#new-projects').load('./index.html',{"name":'張三',"age":12}); }) 3、 //加載文件之后,會有個回調函數,表示加載成功的函數 $('#new-projects').load('./index.html',{"name":'張三',"age":12},function(){ });
11.2,jQuery的getJSON方法
jQuery的AJAX中使用getJSON()方法異步加載JSON格式數據。獲取服務器中的數據,並對數據進行解析,顯示到頁面中。
語法:
$.getJSON(url,[data],[callback]) url參數為請求加載json格式文件的服務器地址,可選項data參數為請求時 發送的數據,callback參數為數據請求成功后執行的函數。 $.getJSON("./data/getJSON.json", function (data) { var str = ""; //初始化保存內容變量 $.each(data, function(index,ele) { $('ul').append("<li>"+ele.name+"</li>") }); })
11.3,jQuery的$.get()方法
$.get() 方法通過 HTTP GET 請求從服務器上請求數據。
語法:
$.get(URL,callback); url參數規定你請求的路徑,是必需參數,callback參數 為數據請求成功后執行的函數 $.get('./data/getJSON.json',function(data,status){ console.log(status); //success 200狀態碼 ok的意思 })
11.4,jQuery的post()方法
與get()方法相比,post()方法多用於以POST方式向服務器發送數據,服務器接收到數據之后,進行處理,並將處理結果返回頁面.
語法:
$.post(URL,data,callback); url參數規定你請求的路徑,是必需參數,可選的data參數是連同請求發送 的數據。可選的callback參數為數據請求成功后執行的函數。 $.post('/index',{name:'張三'},function(data,status){ console.log(status); })
11.5,jQuery的$.ajax()方法
jquery的$.ajax()方法 是做ajax技術經常使用的一個方法。 它的參數很多,總會有一些初學者記不住,在這里,演示幾個經常使用的參數。 后面講django課程的時候老師會詳細講ajax技術的原理。大家先把每個參數做個筆記。
參數如下:
1.url: 要求為String類型的參數,(默認為當前頁地址)發送請求的地址。 2.type: 要求為String類型的參數,請求方式(post或get)默認為get。 注意其他http請求方法,例如put和delete也可以使用,但僅部分瀏覽器支持。 3.timeout: 要求為Number類型的參數,設置請求超時時間(毫秒)。 此設置將覆蓋$.ajaxSetup()方法的全局設置。 4.async: 要求為Boolean類型的參數,默認設置為true,所有請求均為異 步請求。如果需要發送同步請求,請將此選項設置為false。注意,同步請求將 鎖住瀏覽器,用戶其他操作必須等待請求完成才可以執行。 5.cache: 要求為Boolean類型的參數,默認為true(當dataType為script 時,默認為false),設置為false將不會從瀏覽器緩存中加載請求信息。 6.data: 要求為Object或String類型的參數,發送到服務器的數據。如果已 經不是字符串,將自動轉換為字符串格式。get請求中將附加在url后。防止這種 自動轉換,可以查看 processData選項。對象必須為key/value格式,例如 {foo1:"bar1",foo2:"bar2"}轉換為&foo1=bar1&foo2=bar2。如果是數組, JQuery將自動為不同值對應同一個名稱。例如{foo:["bar1","bar2"]}轉換 為&foo=bar1&foo=bar2。 7.dataType: 要求為String類型的參數,預期服務器返回的數據類型。如果 不指定,JQuery將自動根據http包mime信息返回responseXML或responseText, 並作為回調函數參數傳遞。可用的類型如下: xml:返回XML文檔,可用JQuery處 理。 html:返回純文本HTML信息;包含的script標簽會在插入DOM時執行。 script:返回純文本JavaScript代碼。不會自動緩存結果。除非設置了cache參數。 注意在遠程請求時(不在同一個域下),所有post請求都將轉為get請求。 json: 返回JSON數據。 jsonp:JSONP格式。使用SONP形式調用函數時,例如 myurl?callback=?,JQuery將自動替換后一個“?”為正確的函數名,以執行回調 函數。 text:返回純文本字符串。 8.beforeSend: 要求為Function類型的參數,發送請求前可以修改 XMLHttpRequest對象的函數,例如添加自定義HTTP頭。在beforeSend中如果返 回false可以取消本次ajax請求。XMLHttpRequest對象是惟一的參數。 function(XMLHttpRequest){ this; //調用本次ajax請求時傳遞的options參數 } 9.complete:要求為Function類型的參數,請求完成后調用的回調函數(請求 成功或失敗時均調用)。參數:XMLHttpRequest對象和一個描述成功請求類型的 字符串。 function(XMLHttpRequest, textStatus){ this; //調用本次ajax請求時 傳遞的options參數 } 10.success:要求為Function類型的參數,請求成功后調用的回調函數,有兩 個參數。 (1)由服務器返回,並根據dataType參數進行處理后的數據。 (2)描述狀 態的字符串。 function(data, textStatus){ //data可能是xmlDoc、jsonObj、 html、text等等 this; //調用本次ajax請求時傳遞的options參數 } 11.error: 要求為Function類型的參數,請求失敗時被調用的函數。該函數有 3個參數,即XMLHttpRequest對象、錯誤信息、捕獲的錯誤對象(可選)。ajax事 件函數如下: function(XMLHttpRequest, textStatus, errorThrown){ //通常 情況下textStatus和errorThrown只有其中一個包含信息 this; //調用本次ajax請 求時傳遞的options參數 } 12.contentType: 要求為String類型的參數,當發送信息至服務器時,內容 編碼類型默認為"application/x-www-form-urlencoded"。該默認值適合大多數 應用場合。 13.dataFilter: 要求為Function類型的參數,給Ajax返回的原始數據進行預 處理的函數。提供data和type兩個參數。data是Ajax返回的原始數據,type是調 用jQuery.ajax時提供的dataType參數。函數返回的值將由jQuery進一步處理。 function(data, type){ //返回處理后的數據 return data; } 14.dataFilter: 要求為Function類型的參數,給Ajax返回的原始數據進行預 處理的函數。提供data和type兩個參數。data是Ajax返回的原始數據,type是調 用jQuery.ajax時提供的dataType參數。函數返回的值將由jQuery進一步處理。 function(data, type){ //返回處理后的數據 return data; } 15.global: 要求為Boolean類型的參數,默認為true。表示是否觸發全局 ajax事件。設置為false將不會觸發全局ajax事件,ajaxStart或ajaxStop可用於控 制各種ajax事件。 16.ifModified: 要求為Boolean類型的參數,默認為false。僅在服務器數據 改變時獲取新數據。服務器數據改變判斷的依據是Last-Modified頭信息。默認值 是false,即忽略頭信息。 17.jsonp: 要求為String類型的參數,在一個jsonp請求中重寫回調函數的名 字。該值用來替代在"callback=?"這種GET或POST請求中URL參數里的"callback" 部分,例如{jsonp:'onJsonPLoad'}會導致將"onJsonPLoad=?"傳給服務器。 18.username: 要求為String類型的參數,用於響應HTTP訪問認證請求的用戶名。 19.password: 要求為String類型的參數,用於響應HTTP訪問認證請求的密碼。 20.processData: 要求為Boolean類型的參數,默認為true。默認情況下,發送 的數據將被轉換為對象(從技術角度來講並非字符串)以配合默認內容類型 "application/x-www-form-urlencoded"。如果要發送DOM樹信息或者其他不希望 轉換的信息,請設置為false。 21.scriptCharset: 要求為String類型的參數,只有當請求時dataType為"jsonp" 或者"script",並且type是GET時才會用於強制修改字符集(charset)。通常在本地和遠 程的內容編碼不同時使用