簡介 對於WEB應用程式:用戶瀏覽器發送請求,伺服器接收並處理請求,然後返回結果,往往返回就是字元串(HTML),瀏覽器將字元串(HTML)渲染並顯示瀏覽器上。 傳統的web應用簡單的操作需要載入全局的數據,AJAX,Asynchronous JavaScript and XML (非同步的JavaS ...
簡介
對於WEB應用程式:用戶瀏覽器發送請求,伺服器接收並處理請求,然後返回結果,往往返回就是字元串(HTML),瀏覽器將字元串(HTML)渲染並顯示瀏覽器上。
傳統的web應用簡單的操作需要載入全局的數據,AJAX,Asynchronous JavaScript and XML (非同步的JavaScript和XML),一種創建互動式網頁應用的網頁開發技術方案。使用 【JavaScript語言】 以及 相關【瀏覽器提供類庫】 的功能向服務端發送請求,當服務端處理完請求之後,【自動執行某個JavaScript的回調函數】。
PS:以上請求和響應的整個過程是【偷偷】進行的,頁面上無任何感知。XML是一種標記語言,是Ajax在和後臺交互時傳輸數據的格式之一
利用AJAX可以做:
1、註冊時,輸入用戶名自動檢測用戶是否已經存在。
2、登陸時,提示用戶名密碼錯誤
3、刪除數據行時,將行ID發送到後臺,後臺在資料庫中刪除,資料庫刪除成功後,在頁面DOM中將數據行也刪除
一、iframe實現偽ajax
由於HTML標簽的iframe標簽具有局部載入內容的特性,所以可以使用其來偽造Ajax請求。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div> <p>請輸入要載入的地址:<span id="currentTime"></span></p> <p> <input id="url" type="text" /> <input type="button" value="刷新" onclick="LoadPage();"> </p> </div> <div> <h3>載入頁面位置:</h3> <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe> </div> <script type="text/javascript"> window.onload= function(){ var myDate = new Date(); document.getElementById('currentTime').innerText = myDate.getTime(); }; function LoadPage(){ var targetUrl = document.getElementById('url').value; document.getElementById("iframePosition").src = targetUrl; } </script> </body> </html>
二、原生ajax
Ajax主要就是使用 【XmlHttpRequest】對象來完成請求的操作,該對象在主流瀏覽器中均存在(除早起的IE),Ajax首次出現IE5.5中存在(ActiveX控制項)。
XmlHttpRequest對象介紹
XmlHttpRequest對象方法
a. void open(String method,String url,Boolen async)
用於創建請求
參數:
method: 請求方式(字元串類型),如:POST、GET、DELETE...
url: 要請求的地址(字元串類型)
async: 是否非同步(布爾類型)
b. void send(String body)
用於發送請求
參數:
body: 要發送的數據(字元串類型)
c. void setRequestHeader(String header,String value)
用於設置請求頭
參數:
header: 請求頭的key(字元串類型)
vlaue: 請求頭的value(字元串類型)
d. String getAllResponseHeaders()
獲取所有響應頭
返回值:
響應頭數據(字元串類型)
e. String getResponseHeader(String header)
獲取響應頭中指定header的值
參數:
header: 響應頭的key(字元串類型)
返回值:
響應頭中指定的header對應的值
f. void abort()
終止請求
XmlHttpRequest對象的主要屬性:
a. Number readyState 狀態值(整數) 詳細: 0-未初始化,尚未調用open()方法; 1-啟動,調用了open()方法,未調用send()方法; 2-發送,已經調用了send()方法,未接收到響應; 3-接收,已經接收到部分響應數據; 4-完成,已經接收到全部響應數據; b. Function onreadystatechange 當readyState的值改變時自動觸發執行其對應的函數(回調函數) c. String responseText 伺服器返回的數據(字元串類型) d. XmlDocument responseXML 伺服器返回的數據(Xml對象) e. Number states 狀態碼(整數),如:200、404... f. String statesText 狀態文本(字元串),如:OK、NotFound...
跨瀏覽器支持
- XmlHttpRequest
IE7+, Firefox, Chrome, Opera, etc. - ActiveXObject("Microsoft.XMLHTTP")
IE6, IE5
基於原生ajax的實例
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>XMLHttpRequest - Ajax請求</h1> <input type="button" onclick="XmlGetRequest();" value="Get發送請求" /> <input type="button" onclick="XmlPostRequest();" value="Post發送請求" /> <script src="/statics/jquery-1.12.4.js"></script> <script type="text/javascript"> function GetXHR(){ var xhr = null; if(XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; } function XhrPostRequest(){ var xhr = GetXHR(); // 定義回調函數 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 已經接收到全部響應數據,執行以下操作 var data = xhr.responseText; console.log(data); } }; // 指定連接方式和地址----文件方式 xhr.open('POST', "/test/", true); // 設置請求頭 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); // 發送請求 xhr.send('n1=1;n2=2;'); } function XhrGetRequest(){ var xhr = GetXHR(); // 定義回調函數 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 已經接收到全部響應數據,執行以下操作 var data = xhr.responseText; console.log(data); } }; // 指定連接方式和地址----文件方式 xhr.open('get', "/test/", true); // 發送請求 xhr.send(); } </script> </body> </html>
三、jquery的ajax
jQuery其實就是一個JavaScript的類庫,其將複雜的功能做了上層封裝,使得開發者可以在其基礎上寫更少的代碼實現更多的功能。
- jQuery 不是生產者,而是大自然搬運工。
- jQuery Ajax本質 XMLHttpRequest 或 ActiveXObject
註:2.+版本不再支持IE9以下的瀏覽器
方法列表
jQuery.get(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數。 success: 載入成功時回調函數。 dataType: 返回內容格式,xml, json, script, text, html jQuery.post(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數 success: 載入成功時回調函數 dataType: 返回內容格式,xml, json, script, text, html jQuery.getJSON(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數。 success: 載入成功時回調函數。 jQuery.getScript(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數。 success: 載入成功時回調函數。 jQuery.ajax(...) 部分參數: url:請求地址 type:請求方式,GET、POST(1.9.0之後用method) headers:請求頭 data:要發送的數據 contentType:即將發送信息至伺服器的內容編碼類型(預設: "application/x-www-form-urlencoded; charset=UTF-8") async:是否非同步 timeout:設置請求超時時間(毫秒) beforeSend:發送請求前執行的函數(全局) complete:完成之後執行的回調函數(全局) success:成功之後執行的回調函數(全局) error:失敗之後執行的回調函數(全局) accepts:通過請求頭髮送給伺服器,告訴伺服器當前客戶端課接受的數據類型 dataType:將伺服器端返回的數據轉換成指定類型 "xml": 將伺服器端返回的內容轉換成xml格式 "text": 將伺服器端返回的內容轉換成普通文本格式 "html": 將伺服器端返回的內容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript標簽,則會嘗試去執行。 "script": 嘗試將返回值當作JavaScript去執行,然後再將伺服器端返回的內容轉換成普通文本格式 "json": 將伺服器端返回的內容轉換成相應的JavaScript對象 "jsonp": JSONP 格式 使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函數名,以執行回調函數 如果不指定,jQuery 將自動根據HTTP包MIME信息返回相應類型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string converters: 轉換器,將伺服器端的內容根據指定的dataType轉換類型,並傳值給success回調函數 $.ajax({ accepts: { mycustomtype: 'application/x-some-custom-type' }, // Expect a `mycustomtype` back from server dataType: 'mycustomtype' // Instructions for how to deserialize a `mycustomtype` converters: { 'text mycustomtype': function(result) { // Do Stuff return newresult; } }, });
實例
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="button" onclick="XmlSendRequest();" value='Ajax請求' /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', dataType: 'text', success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html>
四、跨域的ajax
由於瀏覽器存在同源策略機制,同源策略阻止從一個源載入的文檔或腳本獲取或設置另一個源載入的文檔的屬性。
特別的:由於同源策略是瀏覽器的限制,所以請求的發送和響應是可以進行,只不過瀏覽器不接受罷了。
瀏覽器同源策略並不是對所有的請求均制約:
- 制約: XmlHttpRequest
- 不叼: img、iframe、script等具有src屬性的標簽
1、JSONP實現跨域請求
JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script標簽的src屬性(瀏覽器允許script標簽跨域)
JSONP的跨域實例
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="button" onclick="Jsonp1();" value='提交'/> </p> <p> <input type="button" onclick="Jsonp2();" value='提交'/> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function Jsonp1(){ var tag = document.createElement('script'); tag.src = "http://c2.com:8000/test/"; document.head.appendChild(tag); document.head.removeChild(tag); } function Jsonp2(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', dataType: 'JSONP', success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html>
2、CORS
隨著技術的發展,現在的瀏覽器可以支持主動設置從而允許跨域請求,即:跨域資源共用(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,使得瀏覽器允許跨域請求。
* 簡單請求 OR 非簡單請求
條件: 1、請求方式:HEAD、GET、POST 2、請求頭信息: Accept Accept-Language Content-Language Last-Event-ID Content-Type 對應的值是以下三個中的任意一個 application/x-www-form-urlencoded multipart/form-data text/plain
註意:同時滿足以上兩個條件時,則是簡單請求,否則為複雜請求
* 簡單請求和非簡單請求的區別?
簡單請求:一次請求
非簡單請求:兩次請求,在發送數據之前會先發一次請求用於做“預檢”,只有“預檢”通過後才再發送一次請求用於數據傳輸。
* 關於“預檢
- 請求方式:OPTIONS - “預檢”其實做檢查,檢查如果通過則允許傳輸數據,檢查不通過則不再發送真正想要發送的消息 - 如何“預檢” => 如果複雜請求是PUT等請求,則服務端需要設置允許某請求,否則“預檢”不通過 Access-Control-Request-Method => 如果複雜請求設置了請求頭,則服務端需要設置允許某請求頭,否則“預檢”不通過 Access-Control-Request-Headers
cors跨域簡單請求
伺服器設置響應頭:Access-Control-Allow-Origin = '功能變數名稱' 或 '*'
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 9 <p> 10 <input type="submit" onclick="XmlSendRequest();" /> 11 </p> 12 13 <p> 14 <input type="submit" onclick="JqSendRequest();" /> 15 </p> 16 17 <script type="text/javascript" src="jquery-1.12.4.js"></script> 18 <script> 19 function XmlSendRequest(){ 20 var xhr = new XMLHttpRequest(); 21 xhr.onreadystatechange = function(){ 22 if(xhr.readyState == 4) { 23 var result = xhr.responseText; 24 console.log(result); 25 } 26 }; 27 xhr.open('GET', "http://c2.com:8000/test/", true); 28 xhr.send(); 29 } 30 31 function JqSendRequest(){ 32 $.ajax({ 33 url: "http://c2.com:8000/test/", 34 type: 'GET', 35 dataType: 'text', 36 success: function(data, statusText, xmlHttpRequest){ 37 console.log(data); 38 } 39 }) 40 } 41 42 43 </script> 44 </body> 45 </html>html
1 class MainHandler(tornado.web.RequestHandler): 2 def get(self): 3 self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 4 self.write('{"status": true, "data": "seven"}')tornado
cors跨域複雜請求
由於複雜請求時,首先會發送“預檢”請求,如果“預檢”成功,則發送真實數據。
- “預檢”請求時,允許請求方式則需伺服器設置響應頭:Access-Control-Request-Method
- “預檢”請求時,允許請求頭則需伺服器設置響應頭:Access-Control-Request-Headers
- “預檢”緩存時間,伺服器設置響應頭:Access-Control-Max-Age
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 9 <p> 10 <input type="submit" onclick="XmlSendRequest();" /> 11 </p> 12 13 <p> 14 <input type="submit" onclick="JqSendRequest();" /> 15 </p> 16 17 <script type="text/javascript" src="jquery-1.12.4.js"></script> 18 <script> 19 function XmlSendRequest(){ 20 var xhr = new XMLHttpRequest(); 21 xhr.onreadystatechange = function(){ 22 if(xhr.readyState == 4) { 23 var result = xhr.responseText; 24 console.log(result); 25 } 26 }; 27 xhr.open('PUT', "http://c2.com:8000/test/", true); 28 xhr.setRequestHeader('k1', 'v1'); 29 xhr.send(); 30 } 31 32 function JqSendRequest(){ 33 $.ajax({ 34 url: "http://c2.com:8000/test/", 35 type: 'PUT', 36 dataType: 'text', 37 headers: {'k1': 'v1'}, 38 success: function(data, statusText, xmlHttpRequest){ 39 console.log(data); 40 } 41 }) 42 } 43 44 45 </script> 46 </body> 47 </html>html
1 class MainHandler(tornado.web.RequestHandler): 2 3 def put(self): 4 self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 5 self.write('{"status": true, "data": "seven"}') 6 7 def options(self, *args, **kwargs): 8 self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 9 self.set_header('Access-Control-Allow-Headers', "k1,k2") 10 self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") 11 self.set_header('Access-Control-Max-Age', 10)tornado
跨域獲取響應頭
預設獲取到的所有響應頭只有基本信息,如果想要獲取自定義的響應頭,則需要再伺服器端設置Access-Control-Expose-Headers。
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 9 <p> 10 <input type="submit" onclick="XmlSendRequest();" /> 11 </p> 12 13 <p> 14 <input type="submit" onclick="JqSendRequest();" /> 15 </p> 16 17 <script type="text/javascript" src="jquery-1.12.4.js"></script> 18 <script> 19 function XmlSendRequest(){ 20 var xhr = new XMLHttpRequest(); 21 xhr.onreadystatechange = function(){ 22 if(xhr.readyState == 4) { 23 var result = xhr.responseText; 24 console.log(result); 25 // 獲取響應頭 26 console.log(xhr.getAllResponseHeaders()); 27 } 28 }; 29 xhr.open('PUT', "http://c2.com:8000/test/", true); 30 xhr.setRequestHeader('k1', 'v1'); 31 xhr.send(); 32 } 33 34 function JqSendRequest(){ 35 $.ajax({ 36 url: "http://c2.com:8000/test/", 37 type: 'PUT', 38 dataType: 'text', 39 headers: {'k1': 'v1'}, 40 success: function(data, statusText, xmlHttpRequest){ 41 console.log(data); 42 // 獲取響應頭 43 console.log(xmlHttpRequest.getAllResponseHeaders()); 44 } 45 }) 46 } 47 48 49 </script> 50 </body> 51 </html>html
1 class MainHandler(tornado.web.RequestHandler): 2 3 def put(self): 4 self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 5 6 self.set_header('xxoo', "seven") 7 self.set_header('bili', "daobidao") 8 9 self.set_header('Access-Control-Expose-Headers', "xxoo,bili") 10 11 12 self.write('{"status": true, "data": "seven"}') 13 14 def options(self, *args, **kwargs): 15 self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 16 self.set_header('Access-Control-Allow-Headers', "k1,k2") 17 self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") 18 self.set_header('Access-Control-Max-Age', 10)tornado
跨域傳輸cookie
在跨域請求中,預設情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無論在預檢請求中或是在實際請求都是不會被髮送。
如果想要發送:
- 瀏覽器端:XMLHttpRequest的withCredentials為true
- 伺服器端:Access-Control-Allow-Credentials為true
- 註意:伺服器端響應的 Access-Control-Allow-Origin 不能是通配符 *
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 9 <p> 10 <input type="submit" onclick="XmlSendRequest();" /> 11 </p> 12 13 <p> 14 <input type="submit" onclick="JqSendRequest();" /> 15 </p> 16 17 <script type="text/javascript" src="jquery-1.12.4.js"></script> 18 <script> 19 function XmlSendRequest(){ 20 var xhr = new XMLHttpRequest(); 21 xhr.onreadystatechange = function(){ 22 if(xhr.readyState == 4) { 23 var result = xhr.responseText; 24 console.log(result); 25 } 26 }; 27 28 xhr.withCredentials = true; 29 30 xhr.open('PUT', "http://c2.com:8000/test/", true); 31 xhr.setRequestHeader('k1', 'v1'); 32 xhr.send(); 33 } 34 35 function JqSendRequest(){ 36 $.ajax({ 37 url: "http://c2.com:8000/test/", 38 type: 'PUT', 39 dataType: 'text', 40 headers: {'k1': 'v1'}, 41 xhrFields:{withCredentials: true}, 42 success: function(data, statusText, xmlHttpRequest){ 43 console.log(data); 44 } 45 }) 46 } 47 48 49 </script> 50 </body> 51 </html>html
1 class MainHandler(tornado.web.RequestHandler): 2 3 def put(self): 4 self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 5 self.set_header('Access-Control-Allow-Credentials', "true") 6 7 self.set_header('xxoo', "seven") 8 self.set_header('bili', "daobidao") 9 self.set_header('Access-Control-Expose-Headers', "xxoo,bili") 10 11 self.set_cookie('kkkkk', 'vvvvv'); 12 13