Ajax 技術核心是 XMLHttpRequest 對象(簡稱 XHR),這是由微軟首先引入的一個特性,其他瀏覽器提供商后來都提供了相同的實現。在 XHR 出現之前,Ajax 式的通信必須借助一些手段來實現,大多數是使用隱藏的框架或內嵌框架。XHR 的出現,提供了向服務器發送請求和解析服務器響應提供了流暢的接口。能夠以異步方式從服務器獲取更多的信息,這就意味着,用戶只要觸發某一事件,在不刷新網頁的情況下,更新服務器最新的數據。雖然 Ajax 中的 x 代表的是 XML,但 Ajax 通信和數據格式無關,也就是說這種技術不一定使用 XML。IE7+、Firefox、Opera、Chrome 都支持原生的 XHR 對象,在這些瀏覽器中創建 XHR 對象可以直接實例化 XMLHttpRequest 即可。
var xhr = new XMLHttpRequest();
alert(xhr); //XMLHttpRequest
了解:較老的 IE 版本創建 Microsoft.XMLHTTP 對象:
var xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
在使用 XHR 對象時,先必須調用 open()方法,它接受三個參數:要發送的請求類型(get、post)、請求的 URL 和表示是否異步。open()方法並不會真正發送請求,而只是啟動一個請求以備發送。通過 send()方法進行發送請求,send()方法接受一個參數,作為請求主體發送的數據。如果不需要則,必須填 null。執行 send()方法之后,請求就會發送到服務器上。
當請求發送到服務器端,收到響應后,響應的數據會自動填充 XHR 對象的屬性。那么一共有四個屬性:
接受響應之后,第一步檢查 status 屬性,以確定響應已經成功返回。一般情況 HTTP 狀態代碼為 200 作為成功的標志。除了成功的狀態代碼,還有一些別的:
我們判斷 HTTP 狀態值即可,不建議使用 HTTP 狀態說明,因為在跨瀏覽器的時候,可能會不太一致。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC > <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> </body> <script> var xhr=new XMLHttpRequest(); console.log(xhr); xhr.open("get","test.json?uname=zs",false) xhr.send(null); if(xhr.status==200){ var text=xhr.responseText; console.log(text); } </script> </html>
同步調用固然簡單,但使用異步調用才是我們真正常用的手段。使用異步調用的時候,檢測 readyState 屬性,每當 readyState 屬性改變時,觸發readystatechange 事件。這個屬性有五個值:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC > <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> </body> <script type="text/javascript"> var xhr=new XMLHttpRequest() console.log(xhr); console.log(xhr.readyState); xhr.open("get","test.json?liu=feng",true); console.log(xhr.readyState); xhr.send(null); xhr.onreadystatechange=function(){ console.log(xhr.readyState); if(xhr.readyState==4){ if(xhr.status==200){ var text=xhr.responseText; console.log(text) } } } </script> </html>
在提供服務器請求的過程中,有兩種方式,分別是:GET 和 POST。在 Ajax 使用的過程中,GET 的使用頻率要比 POST 高。
GET 請求
GET 請求是最常見的請求類型,最常用於向服務器查詢某些信息。必要時,可以將查詢字符串參數追加到 URL 的末尾,以便提交給服務器xhr.open('get','diner/login?'+'name=Lee&age=100',true);通過 URL 后的問號給服務器傳遞鍵值對數據,服務器接收到返回響應數據。特殊字符傳參產生的問題可以使用 encodeURIComponent()進行編碼處理,中文字符的返回及傳參,可以將頁面保存和設置為 utf-8 格式即可,AJAX 返回的數據為 UTF-8
/一個通用的 URL 提交函數
function addURLParam(url, name, value) {
//判斷的 url 是否有已有參數
url += (url.indexOf('?') == -1 ? '?' : '&');
url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
return url;
}
當沒有 encodeURIComponent()方法時,在一些特殊字符比如“&”,會出現錯誤導致無法獲取。
POST 請求
POST 請求可以包含非常多的數據,我們在使用表單提交的時候,很多就是使用的 POST 傳輸方式。
xhr.open('post', 'diner/login', true);
而發送 POST 請求的數據,不會跟在 URL 的尾巴上,而是通過 send()方法向服務器提交數據。
xhr.send('name=Lee&age=100');
一般來說,向服務器發送 POST 請求由於解析機制的原因,需要進行特別的處理。因為POST請求和Web表單提交是不同的,需要使用XHR來模仿表單提交。
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
從性能上來講 POST 請求比 GET 請求消耗更多一些,用相同數據比較,GET最多比 POST 快兩倍。
三、封裝 Ajax
因為 Ajax 使用起來比較麻煩,主要就是參數問題,比如到底使用 GET 還是
POST;我們需要封裝一個 Ajax 函數,來方便我們調用。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC > <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> </body> <script> var obj={ url:"user", data:{name:"zs",age:18}, async:true, success:function(result){ console.log(result); console.log(JSON.parse(result)); }, error:function(result){ console.log(result); } }; ajax(obj); function ajax(obj){ var xhr=new XMLHttpResquest(); obj.data=params(obj.data); if(obj.method.toUpperCase()=="GET"){ obj.url+=(obj.method.indexOf("?")==-1)? "?" +obj.data:"&"+obj.data; xhr.open(obj.mehod,obj.url,obj.async); xhr.send(null); }else{ xhr.open(obj.method,obj.url,obj.async); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencode"); xhr.send(obj.data); } if(obj.async){ xhr.onreadystatechange=function(){ if(xhr.readyState==4){ callback(); } } }else{ callback; } } function callback(){ if(xhr.status==200){ obj.success(xhr.responseText); }else{ obj.error("請求失敗!"+xhr.status+xhr.statusText) } } function params(data){ var arr=[]; if(data!= null && !=""){ for(var d in data){ var name=encodeURICompoent(d); var value=encodeURICompoent(data[d]); arr.push(name+"="+value); } var param=arr.join("&"); return param; } return null; } </script> </html>
import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSON; /** * Servlet implementation class servlet01 */ @WebServlet("/s01") public class servlet01 extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response) */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub System.out.println("servlet"); Map<String, Object> map= new HashMap<>(); map.put("uname", "zs"); map.put("age", 18); map.put("sex", true); String json=JSON.toJSONString(map); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(json); } }
封裝 Ajax 並不是一開始就形成以上的形態,需要經過多次變化而成。
同步:
提交請求->等待服務器處理->處理完畢返回這個期間客戶端瀏覽器不能干任何事。一心一意,當前只能做一件事,其他事情必須等當前的事情完成,才能繼續后面的事情。
異步:
請求通過事件觸發->服務器處理(這時瀏覽器仍然可以做其他事情)->處理完畢 。三心二意:同時可以做多件事情:左手按着空格鍵,右手可以不斷的擊打鼠標,眼睛還要同時看着屏幕,很辛苦。