Ajax基礎
Ajax(Asynchronous JavaScript And XML)概念:
通過XMLHttpRequest對象向服務器提出請求並處理響應,進行頁面的局部更新。
AJAX都有哪些優點和缺點?
ajax的優點:
1、最大的一點是頁面無刷新,用戶的體驗非常好。
2、使用異步方式與服務器通信,具有更加迅速的響應能力。
3、“按需取數據”,可以最大程度的減少冗余請求,和響應對服務器和帶寬的負擔,節約空間和寬帶租用成本。
4、基於標准化的並被廣泛支持的技術,不需要下載插件或者小程序。
ajax的缺點:
1、ajax不支持瀏覽器back按鈕。
2、安全問題 AJAX暴露了與服務器交互的細節。
3、對搜索引擎的支持比較弱。
4、破壞了程序的異常機制。
5、不容易調試。
ajax就會面臨兩個不可避免的問題:
一是以何種格式來減緩數據;
二是如何解決跨域問題。ajax本身不支持跨域請求,需要在服務器端處理--JSONP(一種跨域數據交互協議)。
相關介紹:
現在 W3C 官方都不提倡 XHR 了,而是提倡 FetchAPI(雖然也不好用)
Ajax 指的是 XMLHttpRequest(XHR),未來現在已被 Fetch 替代;
Fetch API 是基於 Promise 設計,有必要先學習一下 Promise
https://www.cnblogs.com/hsprout/p/5504053.html
https://blog.csdn.net/shendeguang/article/details/72818802
https://segmentfault.com/a/1190000003810652
Ajax請求過程
創建XMLHttpRequest、連接服務器、發送請求、服務器做出響應、接收響應數據
瀏覽器端
一:創建XMLHttpRequest對象
由於不同瀏覽器的控件不同,所以為了兼容性,需要根據當前頁面所在瀏覽器以不同方式獲取到XMLHttpRequest對象:先檢查瀏覽器是否支持 XMLHttpRequest 對象。如果支持,則創建 XMLHttpRequest 對象。如果不支持,則創建 ActiveXObject。
var xmlhttp; if (window.XMLHttpRequest) { //檢查瀏覽器的XMLHttpRequest屬性,如果為真則支持XMLHttpRequest // IE7+, Firefox, Chrome, Opera, Safari 瀏覽器支持XMLHttpRequest xmlhttp=new XMLHttpRequest(); } else { // IE6, IE5 瀏覽器使用ActiveXObject xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); }
二:向服務器URL發出請求,傳遞參數
方法 | 描述 |
open(method,url,async) | 請求類型、URL 以及是否異步處理請求。 method:請求的類型;GET 或 POST url:處理請求的文件在服務器上的位置 async:true(異步)或 false(同步) |
send(string) | 將請求發送到服務器。 為Post,則send("para1=val1 & para2=val2...")傳遞參數 |
GET方式:在open()方法的url參數后面拼接參數,然后send()發送一個請求過去即可。
--用於獲取數據(如瀏覽貼子)把數據放在URL(網址)里面來提交;安全性低、容量低、便於分享(將網址發給別人)
POST方式:open()方法URL不攜帶參數,在send()中傳遞參數列表發送請求,並且在發送請求前需要設置請求頭的Content-Type屬性。
--用於上傳數據(如用戶注冊)把數據放在不是URL的地方;安全性一般、容量幾乎無限、不便於分享
而設置回調函數是通過
xmlHttp.onreadystatechange = 回調函數;
實現的,這里注意:回調函數賦值給xmlHttp.onreadystatechange時不能帶(),只是把函數名賦值。
Ajax請求總共有八種Callback:
onSuccess
onFailure
onUninitialized
onLoading
onLoaded
onInteractive
onComplete
onException
XMLHttpRequest對象的常用方法和屬性: open(“method”,”URL”) 方法,建立對服務器的調用 send()方法,發送具體請求 abort()方法,停止當前請求 readyState屬性 請求的狀態 有5個可取值0=未初始化 ,1=正在加載,2=已加載,3=交互中,4=完成 reponseXML 屬性 服務器的響應,表示為XML status 服務器的HTTP狀態碼 框架(架包): dojo, Prototype , JQuery, Dwr, extjs 等等
所以Ajax向服務器發出請求的操作步驟為:
1:通過xmlHttp.open()設置發送請求的目標url,並指明發送方式、是否異步處理請求(一般選true);
2:為xmlHttp.onreadystatechange設置回調函數處理返回結果
3:通過xmlHttp.send()發出請求
GET方式: xmlHttp.open("GET", "url?參數=val & ...", true); xmlHttp.onreadystatechange = callback; xmlHttp.send(null);
POST方式: xmlHttp.open("POST", url, true); xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");//用post方法的話,一定要加這句設置請求頭的contentType屬性 xmlHttp.onreadystatechange = callback; xmlHttp.send("參數=val &..."); //在send方法中傳遞參數。
三:定義回調函數callback,監聽onreadystatechange事件,處理返回結果
屬性 | 描述 |
onreadystatechange | 值是一個函數,每當 readyState 屬性改變時,就會調用該函數。 |
readyState | 存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化。 0: 請求未初始化 1: 服務器連接已建立 2: 請求已接收 3: 請求處理中 4: 請求已完成,且響應已就緒 |
status | 200: 請求處理成功 404: 未找到頁面 |
onreadystatechange 事件
if (xmlhttp.readyState==4 && xmlhttp.status==200){ 處理結果; }else{ 錯誤提示; }
處理結果
服務器與瀏覽器的信息傳遞歸根到底是IO流的傳輸,而IO流傳輸的是字節流、字符流。但是,我們知道簡單的字符串有時候不能很好地表達我們的結果,比如:返回結果是一組對象。這時候我們就可以用某種易於攜帶數據、易解析的字符串來傳遞結果了。在Ajax中,返回的結果類型可以有多種,普通文本、XML、JSON、Html等都可以,而這多種結果類型最終只用xmlhttprequest的兩個屬性獲取:
屬性 | 描述 |
responseText | 獲得字符串形式的響應數據。包括普通文本、json字符串、html字符串 |
responseXML | 獲得 XML 形式的響應數據並解析成xml的document對象。 |
XML格式的結果字符串可以用responseXML獲取並解析成xml的document對象進行結點訪問與內容提取;普通文本、json字符串、html字符串(少用)則通過responseText獲取,普通文本結果直接使用,json字符串通過eval(jsonstring)解析成json對象來使用,html字符串則用來改變html頁面的某處代碼。
if(ID=="getTXT"){ //以普通文本返回: var str = xmlHttp.responseText; } if(ID=="getXML"){ //以xml文檔返回: var xmldoc = xmlHttp.responseXML; var nodes=xmldoc.getElementsByTagName("標簽名"); //按標簽解析為數組 for(var i=0;i<nodes.length;i++) { 提取結點值並使用; } } if(ID=="getJSON"){ //以json文檔返回:json數據的處理統一先用responseText作為一個字符串接收后再轉為json對象進行處理 var str = xmlHttp.responseText; var json = eval('(' + str + ')'); 通過json.XX提取內容 }
服務器端
服務器端定義一個servlet進行請求處理,然后返回結果。
返回結果的步驟:
1:設置響應編碼格式;
2:設置響應的Content-Type;
3:拼接結果字符串:XML格式的結果需要用StringBuffer或StringBuilder來拼接。一定要先加XML標准定義:<?xml version=\"1.0\" encoding=\"utf-8\"?>
4:獲取響應輸出流;
5:通過輸出流向瀏覽器傳輸結果字符串;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String ID = request.getParameter("ID"); if("getTXT".equals(ID)){ getTXT(request, response); }else if("getXML".equals(ID)){ getXML(request, response); }else if("getJSON".equals(ID)){ getJSON(request, response); } } public void getTXT(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain; charset=UTF-8"); PrintWriter out = response.getWriter(); out.write("普通文本值"); out.close(); } public void getXML(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/xml; charset=UTF-8"); PrintWriter out = response.getWriter(); //XML格式的結果需要用StringBuffer或StringBuilder來拼接。切記:一定要先加XML標准定義<?xml version=\"1.0\" encoding=\"utf-8\"?> StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); sb.append("<root><node>結點值</node></root>"); out.write(sb.toString()); out.close(); } public void getJSON(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=UTF-8"); PrintWriter out = response.getWriter(); out.write("{JSON字符串}"); out.close(); }
實例:
//(原生js實現Ajax)實例1: //Ajax封裝函數 function Ajax(type, url, data, success, failed){ // 創建ajax對象 var xhr = null; if(window.XMLHttpRequest){//非IE瀏覽器 xhr = new XMLHttpRequest(); } else if {//IE瀏覽器 xhr = new ActiveXObject('Microsoft.XMLHTTP') }else{ alert("該瀏覽器不支持Ajax!"); } // 用於清除緩存 var random = Math.random(); if(typeof data == 'object'){ var str = ''; for(var key in data){ str += key+'='+data[key]+'&'; } data = str.replace(/&$/, ''); } if(type.toUpperCase() == 'GET'){ if(data){ xhr.open('GET', url + '?' + data, true); } else { xhr.open('GET', url + '?t=' + random, true); } xhr.send(); } else if(type.toUpperCase() == 'POST'){ xhr.open('POST', url, true); // 如果需要像 html 表單那樣 POST 數據,請使用 setRequestHeader() 來添加 http 頭。 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.send(data); } // 處理返回數據 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ /* ** Http狀態碼 ** 1xx :信息展示 ** 2xx :成功 ** 3xx :重定向 ** 4xx : 客戶端錯誤 ** 5xx :服務器端錯誤 */ if(xhr.status == 200){ success(xhr.responseText); } else { if(failed){ failed(xhr.status); } } } } } // 測試調用 var sendData = {name:'asher',sex:'male'}; Ajax('get', 'data/data.html', sendData, function(data){ console.log(data); }, function(error){ console.log(error); });
JSONP實現跨域實例:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSONP實現跨域</title> <script type="text/javascript" src="jquery-1.10.2.js"></script> </head> <script type="text/javascript"> $(function(){ /* //簡寫形式,效果相同 $.getJSON("http://app.example.com/base/json.do?sid=1494&busiId=101&jsonpCallback=?", function(data){ $("#showcontent").text("Result:"+data.result) }); */ $.ajax({ type : "post", async:false, // 使用同步操作 url : "http://10.64.22.11/service/promotion/intention/intentionResult?token=5f25d0b83d774abd941aa5309bf081f7&userid=4221", dataType : "jsonp",//數據類型為jsonp jsonp: "jsonpCallback",//服務端用於接收callback調用的function名的參數 success : function(data){ $("#showcontent").text("Result:"+data.result) }, error:function(){ alert('fail'); } }); }); </script> <body> <div id="showcontent">請求結果:</div> </body> </html>