這裏將本身這段時間學習的關於先後臺數據交互的筆記寫在這裏,這裏包含了Django傳輸數據給JS,AJAX的相關問題,跨域問題,如何解決AJAX的跨域問題等等。比較凌亂,請看到這篇博客的盆友見諒,若是我將最近學習的這段內容理清楚了,我會再寫一篇易於理解的文章作以鞏固。javascript
有時候咱們想把一個list或者dict等JSON對象傳到網頁的JavaScript,用JS進行處理,好比用JS將數據可視化顯示到網頁上,這裏說兩種:html
1,直接在視圖函數中渲染一個list或者dict的內容,和網頁其餘部分一塊兒顯示到網頁(一次性的渲染,並且是同一次請求)前端
2,頁面加載完成後,在頁面操做,在頁面上經過AJAX方法獲得新的數據(再向服務器發送一次請求)並顯示在網頁上,在這種狀況適用於頁面不刷新的狀況下,動態加載一些內容。好比用戶輸入一個值或者點擊某個地方,動態的把相應內容顯示在網頁上。java
這個例子是把一個list傳遞給JavaScript,而後通過處理後顯示到網頁上,好比可能須要JS進行可視化數據。python
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')), ]
from django.urls import path from user12 import views urlpatterns = [ path('login/', views.login) ]
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序列化的數據類型可轉化便可)jquery
<!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技術。web
Asynchronous JavaScript and XML (異步的JavaScript和XML),他不是某種編程語言,而是一種在無需刷新整個網頁的狀況下可以更新部分網頁的技術。ajax
Ajax是使用JavaScript技術向服務器發送異步請求,其實他是一種js技術。django
Ajax 有兩大特性,也是它的優勢。編程
客戶端發出一個請求後,無需等待服務器響應結束,就能夠發出第二個請求
這一特色給用戶的感覺就是在不知不覺中完成請求和響應
<!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>
舉個例子,網站的輸入界面,當輸入關鍵詞的時候,會彈出你想輸入的東西,以下:
當咱們在百度輸入「python」後,會立馬出現一個下拉列表! 列表中顯示的是包含「Python」字的四個關鍵字。其實這就使用了AJAX技術,當文本框發生了輸入變化時,瀏覽器會使用AJAX技術向服務器發送一個請求,查詢包含「python」字的前10個關鍵字,而後服務器會把查詢到的結果響應給瀏覽器,最後瀏覽器把這四個關鍵字顯示在下拉列表中。
Ajax是使用JavaScript技術向服務器發送異步請求,其實他是一種js技術,接下來咱們使用更簡潔的JQuery寫兩個ajax的例子,看看它的工做原理。
在這裏咱們僅發送一個簡單的字符串。
<!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端的返回值。
from django.shortcuts import render import json # Create your views here. def ajax_submit(request): # 客戶端發來的數據 print(request.POST) return render(request, 'user12/ajax1.html')
from django.urls import path from user12 import views urlpatterns = [ path('ajax_submit/', views.ajax_submit), ]
在這裏咱們僅發送一個列表中包含字典數據類型。
因爲發送的數據類型是列表 字典的格式,咱們提早要把他們轉換成字符串形式,不然後臺程序接收到的數據格式不是咱們想要的類型,因此在ajax傳輸數據時須要JSON。
<!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>
from django.shortcuts import render # Create your views here. def ajax_submit_set(request): # 客戶端發送過來的數據 print(request.POST) return render(request, 'user13/ajax1.html')
from django.urls import path from user13 import views urlpatterns = [ path('ajax_submit_set/', views.ajax_submit_set), ]
success:function(arg) {}
若是ajax提交數據成功,那麼就會自動執行這裏的函數。
其實AJAX就是在JavaScript中添加了一個對象:XMLHttpRequest對象。全部的異步交互都是使用XMLHttpRequest對象完成的。也就是說,咱們只須要學習一個JavaScript的新對象便可。
var xmlHttp = new XMLHttpRequest();(大多數瀏覽器都支持DOM2規範)
注意:各個瀏覽器對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; }
當獲得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);
當使用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鏈接
當請求發送出去後,服務器端Servlet 就開始執行了,可是服務器端的響應尚未接收到。接下來咱們來接收服務器的響應。
XMLHttpRequest對象有一個onreadystatechange事件,它會在XMLHttpRequest對象的狀態發生變化時被調用。下面介紹一下XMLHttpRequest對象的5種狀態:
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); } };
1,須要設置請求頭:
xmlHttp.setRequestHeader(「Content-Type」, 「application/x-www-form-urlencoded」);
注意:form表單會默認這個鍵值對不設定,Web服務器會忽略請求體的內容
2,在發送的時候就能夠指定請求體了
xmlHttp.send(「username=james&password=123」)
下面將參數的默認使用方式總結以下:
data: 當前ajax請求要攜帶的數據,是一個object對象,ajax方法就會默認地把 它編碼成某種格式(urlencoded:?a=1&b=2)發送給服務端;此外,ajax默認以get方 式發送請求。 contentType:"application/x-www-form-urlencoded"。發送信息至服務器時內容 編碼類型。用來指明當前請求的數據編碼格式;urlencoded:?a=1&b=2;
上述這種默認參數形式,data中的csrf跨站請求僞造鍵值對會被中間件自動識別,contentType參數還有以下一種形式,介紹以下:
contentType:"application/json",即向服務器發送一個json字符串。 注意:contentType:"application/json"一旦設定,data必須是json字符串,不能是json對象
這種類型,使用request.POST 沒法顯示,這種類型要使用 request.body才能顯示數據。
建立XMLHttpRequest對象; 調用open()方法打開與服務器的鏈接; 調用send()方法發送請求; 爲XMLHttpRequest對象指定onreadystatechange事件函數,這個函數會在 XMLHttpRequest的一、二、三、4,四種狀態時被調用; XMLHttpRequest對象的5種狀態,一般咱們只關心4狀態。 XMLHttpRequest對象的status屬性表示服務器狀態碼,它只有在readyState爲 4時才能獲取到。 XMLHttpRequest對象的responseText屬性表示服務器響應內容,它只有在 readyState爲4時才能獲取到!
jQuery底層AJAX實現,簡單易用的高層實現$.get ,$.post等,後端返回的數據會被當作ajax的success回調函數中的data參數,回調函數success的status的成功時返回值若是打印出來是success,獲取值失敗的時候什麼都作不出來。
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
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
//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) }
在註冊表單中,當用戶填寫了用戶名後,把光標移開後,會自動向服務器發送異步請求。服務器返回true或false,返回true表示這個用戶名已經被註冊過,返回false表示沒有註冊過。
客戶端獲得服務器返回的結果後,肯定是否在用戶名文本框後顯示「用戶名已被註冊」的錯誤信息!
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>
<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跨域操做的。
<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 () { } } });
<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 請求的時候,指定這個回調函數名。
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
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實例
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實例
$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, });
URL由協議,域名,端口和路徑組成,若是兩個URL的協議,域名和端口相同,則表示他們同源。相反,只要協議,域名,端口有任何一個的不一樣,就當被當作的跨域。
舉個例子,對於http://store.company.com/dir/page.html進行同源檢測:
瀏覽器有一個很重要的概念——同源策略(Same-Origin-Policy)。所謂同源是指,域名,協議,端口相同。不一樣源的客戶端腳本(JavaScript, ActionScript)在沒有明確受權的狀況下,不能讀寫對方的資源。
同源策略是一種約定,它是瀏覽器最核心也是最基本的安全功能,若是缺失了同源策略,則瀏覽器的正常功能可能都會受到影響,能夠說Web是構建在同源策略基礎之上的。
同源策略是瀏覽器的一個安全功能,不一樣源的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方資料。因此百度下的js腳本採用ajax讀取京東里面的文件數據是會被拒絕的。
瀏覽器採用同源策略,禁止頁面加載或者執行與自身來源不一樣的域的任何腳本。換句話說瀏覽器禁止的是來自不一樣源的「document」或者腳本,對當前「document」讀取或者設置某些屬性。
情景:
若是Web世界沒有同源策略,當你登陸淘寶帳號並打開另外一個站點時,這個站點上的JavaScript 能夠跨域讀取你的淘寶帳號數據,這樣整個Web世界就無隱私可言了。
好比一個惡意網站的頁面經過iframe嵌入了銀行的登陸頁面(兩者不一樣源),若是沒有同源限制,惡意網站上的JavaScript腳本就能夠在用戶登陸銀行的時候獲取用戶名和密碼。
頁面中的連接,重定向以及表單提交是不會受到同源策略限制的。
跨域資源的引入是能夠的,可是js不能讀寫加載的內容,如<script>、<img>、<iframe>、<link>這些包含 src 屬性的標籤能夠加載跨域資源。但瀏覽器限制了JavaScript的權限使其不能讀、寫加載的內容。
跨域是指從一個域的網頁去請求另外一個域的資源。好比從http://www.baidu.com/ 頁面去請求 http://www.google.com 的資源。
一個域名地址的組成
協議: http:// 子域名:www. 主域名:abc.com 端口號:8080 請求資源地址:script/jquery.js
當協議,子域名,主域名,端口號中任意一個不相同時,都算做不一樣域。不一樣域之間相互請求資源,就算作跨域。JavaScript處於安全方面的考慮,不容許跨域調用其餘頁面的對象。
1,代理
經過在同域名的Web服務器端建立一個代理
2,JSONP
JSONP 只支持GET請求
3,XHR2
HTML5 提供的XMLHttpRequest Level2:支持跨域訪問(IE10如下不支持)
說到AJAX就會不可避免的面臨兩個問題,第一個是AJAX以何種格式來交換數據?第二個是跨域的需求如何解決?這兩個問題目前都有不一樣的解決方案,好比數據能夠用自定義字符串或者用XML來描述,跨域能夠經過服務器端代理來解決。但到目前爲止最被推崇或者說首選的方案仍是用JSON來傳數據,靠JSONP來跨域。
JSON和JSONP雖然只有一個字母的差異,但其實他們根本不是一回事兒:JSON是一種數據交換格式,而JSONP是一種依靠開發人員的聰明才智創造出的一種非官方跨域數據交互協議。咱們拿最近比較火的諜戰片來打個比方,JSON是地下黨們用來書寫和交換情報的「暗號」,而JSONP則是把用暗號書寫的情報傳遞給本身同志時使用的接頭方式。看到沒?一個是描述信息的格式,一個是信息傳遞雙方約定的方法。
JSONP是JSON with Padding的略稱。可讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。jsonp:是 JSON + Padding,json填充。
jsonp是json用來跨域的一個東西,原理是經過script標籤的跨域特性來繞過同源策略。它是一個非官方的協議,它容許在服務器端集成Script tags返回至客戶端,經過JavaScript callback的形式實現跨域訪問(這僅僅是JSONP簡單的實現形式)。
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)
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()
jQuery load()方法是簡單但強大的AJAX方法。
load()方法從服務器加載數據,並把返回的數據放入被選元素中。
語法:
$("selector").load(url,data,callback); 必須的url參數規定記載的url地址 可選的data參數規定與請求一同發送的查詢字符串鍵/值對的集合 可選的callback參數是load()方法完成後所執行的函數名稱 一、 $('#btn').click(function(){ //只傳一個url,表示在id爲#new-projects的元素里加載index.html $('#new-projects').load('./index.html'); }) 二、 $('#btn').click(function(){ //只傳一個url,導入的index.html文件含有多個傳遞參數,相似於:index/html?name='張三' $('#new-projects').load('./index.html',{"name":'張三',"age":12}); }) 三、 //加載文件以後,會有個回調函數,表示加載成功的函數 $('#new-projects').load('./index.html',{"name":'張三',"age":12},function(){ });
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>") }); })
$.get() 方法經過 HTTP GET 請求從服務器上請求數據。
語法:
$.get(URL,callback); url參數規定你請求的路徑,是必需參數,callback參數 爲數據請求成功後執行的函數 $.get('./data/getJSON.json',function(data,status){ console.log(status); //success 200狀態碼 ok的意思 })
與get()方法相比,post()方法多用於以POST方式向服務器發送數據,服務器接收到數據以後,進行處理,並將處理結果返回頁面.
語法:
$.post(URL,data,callback); url參數規定你請求的路徑,是必需參數,可選的data參數是連同請求發送 的數據。可選的callback參數爲數據請求成功後執行的函數。 $.post('/index',{name:'張三'},function(data,status){ console.log(status); })
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)。一般在本地和遠 程的內容編碼不一樣時使用