IE5是第一款引入XHR對象的瀏覽器,在IE5中,XHR對象是經過MSXML庫中的一個ActiveX對象實現的javascript
//適用於 IE7 以前的版本 function createXHR(){ if (typeof arguments.callee.activeXString != "string"){ var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i, len; for (i=0,len=versions.length; i < len; i++){ try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex){ //跳過 } } } return new ActiveXObject(arguments.callee.activeXString); }
IE7+、Firefox、Opera、Chrome、Safari都支持原生的XHR對象,這些瀏覽器中建立XHR對象,可使用XMLHttpRequest構造函數php
var xhr=new XMLHttpRequest();
若是還必需要支持IE的更早版本,能夠在createHXR()函數中加入對原生XHR對象的支持java
function createXHR(){ if (typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined"){ if (typeof arguments.callee.activeXString != "string"){ var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i, len; for (i=0,len=versions.length; i < len; i++){ try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex){ //跳過 } } } return new ActiveXObject(arguments.callee.activeXString); } else { throw new Error("No XHR object available."); } }
這個函數中新增的代碼首先檢測原生XHR對象是否存在,若是存在則返回它的新實例,若是原生對象不存在,則檢測ActiveX對象,若是這兩種對象都不存在,就拋出一個錯誤,而後就可使用下面的代碼在全部瀏覽器中建立XHR對象了算法
var xhr=createXHR();
在使用XHR對象時,要調用的第一個方法是open(),接收3個參數:要發送的請求的類型(get或者post)、請求的URL和表示是否異步發送請求的布爾值json
xhr.open("get","example.php",false);
要想發送特定的請求,調用send()方法跨域
xhr.open("get","example.txt",false); xhr.send(null);
響應的數據會自動填充XHR對象的屬性瀏覽器
XHR對象的readyState屬性表示請求響應過程的當前活動階段緩存
必須在調用open()以前指定onreadystatechange事件處理程序才能確保跨瀏覽器兼容性安全
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "example.txt", true); xhr.send(null);
在發送XHR請求的同時,還會發送下列頭部信息服務器
setRequestHeader()方法,能夠設置自定義的請求頭部信息,這個方法接收兩個參數:頭部字段名稱和頭部字段的值。要成功發送頭部信息,必須在調用open()方法以後且調用send()方法以前調用setRequestHeader()
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "example.php", true); xhr.setRequestHeader("MyHeader", "MyValue"); xhr.send(null);
查詢字符串中每一個參數的名稱和值都必須使用encodeURIComponent()進行編碼,而後才能放到URL的末尾,並且全部的名-值對都必須由&分隔
xhr.open("get","example.php?name1=value1&name2=value2",true)
向現有URL的末尾添加查詢字符串參數
function addURLParam(url, name, value) { url += (url.indexOf("?") == -1 ? "?" : "&"); url += encodeURIComponent(name) + "=" + encodeURIComponent(value); return url; }
POST請求,一般用於向服務器發送應該被保存的數據
function submitData(){ var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("post", "postexample.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); var form = document.getElementById("user-info"); xhr.send(serialize(form)); }
FormData爲序列化表單以及建立與表單格式相同的數據,提供了便利
var data=new FormData(); data.append("name","Nicholas");
建立了FormData的實例後,能夠將它直接傳給XHR的send()方法
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("post","postexample.php", true); var form = document.getElementById("user-info"); xhr.send(new FormData(form));
IE8爲XHR對象添加了一個timeout屬性,表示請求在等待響應多少毫秒以後就會終止,在給timeout設置一個數值後,若是在規定的時間內瀏覽器尚未接收到響應,那麼就會觸發timeout事件,進而會調用ontimeout事件處理程序
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ try { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } catch (ex){ //假設由 ontimeout 事件處理程序處理 } } }; xhr.open("get", "timeout.php", true); xhr.timeout = 1000; // 將超時設置爲 1 秒鐘(僅適用於 IE8+ ) xhr.ontimeout = function(){ alert("Request did not return in a second."); }; xhr.send(null);
經過調用overrideMimeType()方法,能夠保證把響應當作XML而非純文原本處理
var xhr = createXHR(); xhr.open("get", "text.php", true); xhr.overrideMimeType("text/xml"); xhr.send(null);
6個進度事件
var xhr = createXHR(); xhr.onload = function(){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } }; xhr.open("get", "altevents.php", true); xhr.send(null);
var xhr = createXHR(); xhr.onload = function(event){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } }; xhr.onprogress = function(event){ var divStatus = document.getElementById("status"); if (event.lengthComputable){ divStatus.innerHTML = "Received " + event.position + " of " + event.totalSize +" bytes"; } }; xhr.open("get", "altevents.php", true); xhr.send(null);
微軟在IE8中引入了XDR類型,這個對象與XHR類型,可是能實現安全可靠的跨域通訊
全部XDR請求都是異步執行的,不能用它來建立同步請求,請求返回以後,會觸發load事件,響應的數據也會保存在responseText屬性中
var xdr = new XDomainRequest(); xdr.onload = function(){ alert(xdr.responseText); }; xdr.open("get", "http://www.somewhere-else.com/page/"); xdr.send(null)
請求返回前調用abort()方法能夠終止請求
xdr.abort();//終止請求
與XHR同樣,XDR對象也支持timeout屬性以及ontimeout事件處理程序
var xdr = new XDomainRequest(); xdr.onload = function(){ alert(xdr.responseText); }; xdr.onerror = function(){ alert("An error occurred."); }; xdr.timeout = 1000; xdr.ontimeout = function(){ alert("Request took too long."); }; xdr.open("get", "http://www.somewhere-else.com/page/"); xdr.send(null);
爲支持POST請求,XDR對象提供了contentType屬性,用來表示發送數據的格式
var xdr = new XDomainRequest(); xdr.onload = function(){ alert(xdr.responseText); }; xdr.onerror = function(){ alert("An error occurred."); }; xdr.open("post", "http://www.somewhere-else.com/page/"); xdr.contentType = "application/x-www-form-urlencoded"; xdr.send("name1=value1&name2=value2");
要請求位於另外一個域中的資源,使用標準的XHR對象並在open()方法中傳入絕對URL
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "http://www.somewhere-else.com/page/", true); xhr.send(null);
安全限制
這種請求使用OPITONS方法,發送下列頭部
Origin: http://www.nczonline.net Access-Control-Request-Method: POST Access-Control-Request-Headers: NCZ
服務器能夠決定是否容許這種類型的請求,服務器在響應中發送以下頭部與瀏覽器進行溝通
Access-Control-Allow-Origin: http://www.nczonline.net Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: NCZ Access-Control-Max-Age: 1728000
經過將withCredentials屬性設置爲true,能夠指定某個請求應該發送憑據
Access-Control-Allow-Credentials:true
function createCORSRequest(method, url){ var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr){ xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined"){ vxhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; } var request = createCORSRequest("get", "http://www.somewhere-else.com/page/"); if (request){ request.onload = function(){ //對 request.responseText 進行處理 }; request.send(); }
Firefox、Safari和Chrome中的XMLHttpRequest對象與IE中的XDomainRequest對象相似,都提供了夠用的接口,這兩個對象共同的屬性方法以下
經過圖像Ping,瀏覽器得不到任何具體的數據,但經過偵聽load和error事件,它能知道響應何時接收到的
var img = new Image(); img.onload = img.onerror = function(){ alert("Done!"); }; img.src = "http://www.example.com/test?name=Nicholas";
JSONP由兩部分組成:回調函數和數據,回調函數是當響應到來時應該在頁面中調用的函數,回調函數的名字通常是在請求中指定的,而數據就是傳入回調函數中的JSON數據
function handleResponse(response){ alert("You’re at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name); } var script = document.createElement("script"); script.src = "http://freegeoip.net/json/?callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild);
兩種實現Comet的方式
長輪詢
流
在頁面的整個生命週期內只使用一個HTTP鏈接,具體來講就是瀏覽器向服務器發送一個請求,而服務器保持鏈接打開,而後週期性的向瀏覽器發送數據
function createStreamingClient(url, progress, finished){ var xhr = new XMLHttpRequest(), received = 0; xhr.open("get", url, true); xhr.onreadystatechange = function(){ var result; if (xhr.readyState == 3){ //只取得最新數據並調整計數器 result = xhr.responseText.substring(received); received += result.length; //調用 progress 回調函數 progress(result); } else if (xhr.readyState == 4){ finished(xhr.responseText); } }; xhr.send(null); return xhr; } var client = createStreamingClient("streaming.php", function(data){ alert("Received: " + data); }, function(data){ alert("Done!"); });
SSE是圍繞只讀Comet交互推出的API或者模式
var source=new EventSource("myevents.php");
另外還有三個事件
要建立Web Socket,先實例一個WebSocket對象並傳入要鏈接的URL
var socket = new WebSocket("ws://www.example.com/server.php");
實例化WebSocket對象後,瀏覽器會立刻嘗試建立鏈接,與XHR相似,WebSocket也有一個表示當前狀態的readyState屬性,這個屬性的值與XHR並不相同
要關閉Web Socket鏈接,能夠在任什麼時候候調用close()方法
socket.close();
使用send()方法並傳入任意字符串
var socket = new WebSocket("ws://www.example.com/server.php"); socket.send("Hello world!"); //將數據序列化爲JSON字符串,而後發送到服務器 var message = { time: new Date(), text: "Hello world!", clientId: "asdfp8734rew" }; socket.send(JSON.stringify(message)); //當服務器收到消息時,WebSocket對象就會觸發message事件,這個message事件與其餘傳遞消息的協議相似,也是把返回的數據保存在event.data屬性中 socket.onmessage = function(event){ var data = event.data; //處理數據 };
其餘事件
var socket = new WebSocket("ws://www.example.com/server.php"); socket.onopen = function(){ alert("Connection established."); }; socket.onerror = function(){ alert("Connection error."); }; socket.onclose = function(){ alert("Connection closed."); };
考慮是使用 SSE 仍是使用 Web Sockets 時,能夠考慮以下幾個因素。
爲確保經過 XHR 訪問的 URL 安全,通行的作法就是驗證發送請求者是否有權限訪問相應的資源