要真正實現這種絢麗的奇蹟,必須很是熟悉一個 JavaScript 對象,即 XMLHttpRequest。javascript
下面給出將要用於該對象的不多的幾個 方法和屬性。php
·open():創建到服務器的新請求。
·send():向服務器發送請求。
·abort():退出當前請求。
·readyState:提供當前 HTML 的就緒狀態。
·responseText:服務器返回的請求響應文本。 java
1. 建立新的 XMLHttpRequest 對象程序員
<script language="javascript" type="text/javascript">
var request = new XMLHttpRequest();
</script>正則表達式
在 JavaScript 中用 var 建立一個變量,給它一個名字(如 「request」),而後賦給它一個新的 XMLHttpRequest 實例。此後就能夠在函數中使用該對象了。編程
錯誤處理數組
在實際上各類事情均可能出錯,而上面的代碼沒有提供任何錯誤處理。較好的辦法是建立該對象,並在出現問題時優雅地退出。瀏覽器
2.建立具備錯誤處理能力的 XMLHttpRequest安全
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (failed) { request = false; } if (!request) alert("Error initializing XMLHttpRequest!"); </script>
一、建立一個新變量 request 並賦值 false。後面將使用 false 做爲斷定條件,它表示尚未建立 XMLHttpRequest 對象。
二、增長 try/catch 塊:
1)嘗試建立 XMLHttpRequest 對象。
2)若是失敗(catch (failed))則保證 request 的值仍然爲 false。
三、檢查 request 是否仍爲 false(若是一切正常就不會是 false)。
四、若是出現問題(request 是 false)則使用 JavaScript 警告通知用戶出現了問題。 服務器
增長對 Microsoft 瀏覽器IE6(如下)的支持
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); </script>
一、建立一個新變量 request 並賦值 false。使用 false 做爲判斷條件,它表示尚未建立 XMLHttpRequest 對象。
二、增長 try/catch 塊:
1)嘗試建立 XMLHttpRequest 對象。
2)若是失敗(catch (trymicrosoft)):
1>嘗試使用較新版本的 Microsoft 瀏覽器建立 Microsoft 兼容的對象(Msxml2.XMLHTTP)。
2> 若是失敗(catch (othermicrosoft))嘗試使用較老版本的 Microsoft 瀏覽器建立 Microsoft 兼容的對象(Microsoft.XMLHTTP)。
2)若是失敗(catch (failed))則保證 request 的值仍然爲 false。
三、檢查 request 是否仍然爲 false(若是一切順利就不會是 false)。
四、若是出現問題(request 是 false)則使用 JavaScript 警告通知用戶出現了問題。
全部這些代碼都直接嵌套在 script 標記中。像這種不放到方法或函數體中的 JavaScript 代碼稱爲靜態 JavaScript。就是說代碼是在頁面顯示給用戶以前的某個時候運行。(雖然根據規範不能徹底精確地 知道這些代碼什麼時候運行對瀏覽器有什麼影響,可是能夠保證這些代碼在用戶可以與頁面交互以前運行。)這也是多數 Ajax 程序員建立 XMLHttpRequest 對象的通常方式。
將 XMLHttpRequest 建立代碼移動到方法中
<script language="javascript" type="text/javascript"> var request; function createRequest() { try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); } </script>
使用 XMLHttpRequest 的建立方法
<script language="javascript" type="text/javascript"> var request; function createRequest() { try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); } function getCustomerInfo() { createRequest(); // Do something with the request variable } </script>
此代碼唯一的問題是推遲了錯誤通知,這也是多數 Ajax 程序員不採用這一方法的緣由。假設一個複雜的表單有 10 或 15 個字段、選擇框等,當用戶在第 14 個字段(按照表單順序從上到下)輸入文本時要激活某些 Ajax 代碼。這時候運行 getCustomerInfo() 嘗試建立一個 XMLHttpRequest 對象,但(對於本例來講)失敗了。而後向用戶顯示一條警告,明確地告訴他們不能使用該應用程序。但用戶已經花費了不少時間在表單中輸入數據!這是很是使人討厭的,而討厭顯然不會吸引用戶再次訪問您的網站。
用 XMLHttpRequest 發送請求
獲得請求對象以後就能夠進入請求/響應循環了。記住,XMLHttpRequest 唯一的目的是讓您發送請求和接收響應。其餘一切都是 JavaScript、CSS 或頁面中其餘代碼的工做:改變用戶界面、切換圖像、解釋服務器返回的數據。準備好 XMLHttpRequest 以後,就能夠向服務器發送請求了。
Ajax 採用一種沙箱安全模型。所以,Ajax 代碼(具體來講就是 XMLHttpRequest 對象)只能對所在的同一個域發送請求。
設置服務器 URL
創建請求 URL
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); } </script>
Break Neck Pizza 表單
<body> <p><img src="breakneck-logo_4c.gif" alt="Break Neck Pizza" /></p> <form action="POST"> <p>Enter your phone number: <input type="text" size="14" name="phone" id="phone" onChange="getCustomerInfo();" /> </p> <p>Your order will be delivered to:</p> <div id="address"></div> <p>Type your order in here:</p> <p><textarea name="order" rows="6" cols="50" id="order"></textarea></p> <p><input type="submit" value="Order Pizza" id="submit" /></p> </form> </body>
當用戶輸入電話號碼或者改變電話號碼時,將觸發getCustomerInfo() 方法。該方法取得電話號碼並構造存儲在 url 變量中的 URL 字符串。記住,因爲 Ajax 代碼是沙箱型的,於是只能鏈接到同一個域,實際上 URL 中不須要域名。該例中的腳本名爲 /cgi-local/lookupCustomer.php。最後,電話號碼做爲 GET 參數附加到該腳本中:"phone=" + escape(phone)。
若是之前沒用見過 escape() 方法,它用於轉義不能用明文正確發送的任何字符。好比,電話號碼中的空格將被轉換成字符 %20,從而可以在 URL 中傳遞這些字符。
能夠根據須要添加任意多個參數。好比,若是須要增長另外一個參數,只須要將其附加到 URL 中並用 「與」(&)字符分開 [第一個參數用問號(?)和腳本名分開]。
打開請求
有了要鏈接的 URL 後就能夠配置請求了。能夠用 XMLHttpRequest 對象的 open() 方法來完成。該方法有五個參數:
request-type:發送請求的類型。典型的值是 GET 或 POST,但也能夠發送 HEAD 請求。
url:要鏈接的 URL。
asynch:若是但願使用異步鏈接則爲 true,不然爲 false。該參數是可選的,默認爲 true。
username:若是須要身份驗證,則能夠在此指定用戶名。該可選參數沒有默認值。
password:若是須要身份驗證,則能夠在此指定口令。該可選參數沒有默認值。
open() 是打開嗎?
Internet 開發人員對 open() 方法到底作什麼沒有達成一致。但它實際上並非 打開一個請求。若是監控 XHTML/Ajax 頁面及其鏈接腳本之間的網絡和數據傳遞,當調用 open() 方法時將看不到任何通訊。
一般使用其中的前三個參數。事實上,即便須要異步鏈接,也應該指定第三個參數爲 「true」。這是默認值,但堅持明確指定請求是異步的仍是同步的更容易理解。
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); }
一旦用 open() 配置好以後,就能夠發送請求了。幸運的是,發送請求的方法的名稱要比 open() 適當,它就是 send()。
send() 只有一個參數,就是要發送的內容。可是在考慮這個方法以前,回想一下前面已經經過 URL 自己發送過數據了:
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
雖然可使用 send() 發送數據,但也能經過 URL 自己發送數據。事實上,GET 請求(在典型的 Ajax 應用中大約佔 80%)中,用 URL 發送數據要容易得多。若是須要發送安全信息或 XML,可能要考慮使用 send() 發送內容
。若是不須要經過 send() 傳遞數據,則只要傳遞 null 做爲該方法的參數便可。
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.send(null); }
XMLHttpRequest 的一個簡單屬性 onreadystatechange。
由於是異步請求,因此 JavaScript 方法(例子中的 getCustomerInfo())不會等待服務器。所以代碼將繼續執行,就是說,將退出該方法而把控制返回給表單。用戶能夠繼續輸入信息,應用程序不會等待服務器。
這就提出了一個有趣的問題:服務器完成了請求以後會發生什麼?答案是什麼也不發生,至少對如今的代碼而言如此!顯然這樣不行,所以服務器在完成經過 XMLHttpRequest 發送給它的請求處理以後須要某種指示說明怎麼作。
在 JavaScript 中引用函數:
JavaScript 是一種弱類型的語言,能夠用變量引用任何東西。所以若是聲明瞭一個函數 updatePage(),JavaScript 也將該函數名看做是一個變量。換句話說,可用變量名 updatePage 在代碼中引用函數。
設置回調方法
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.onreadystatechange = updatePage; request.send(null); }
須要特別注意的是該屬性在代碼中設置的位置 —— 它是在調用 send() 以前 設置的。發送請求以前必須設置該屬性,這樣服務器在回答完成請求以後才能查看該屬性。如今剩下的就只有編寫 updatePage() 方法了
處理服務器響應
用戶高興地使用 Web 表單(同時服務器在處理請求),而如今服務器完成了請求處理。服務器查看 onreadystatechange 屬性肯定要調用的方法。除此之外,能夠將您的應用程序看做其餘應用程序同樣,不管是否異步。換句話說,不必定要採起特殊的動做編寫響應服務器的方法,只須要改變表單,讓用戶訪問另外一個 URL 或者作響應服務器須要的任何事情。
如今咱們已經看到如何告訴服務器完成後應該作什麼:將 XMLHttpRequest 對象的 onreadystatechange 屬性設置爲要運行的函數名。這樣,當服務器處理完請求後就會自動調用該函數。也不須要擔憂該函數的任何參數。咱們從一個簡單的方法開始
回調方法的代碼
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.onreadystatechange = updatePage; request.send(null); } function updatePage() { alert("Server is done!"); } </script>
它僅僅發出一些簡單的警告,告訴您服務器何時完成了任務。
根據瀏覽器的不一樣,在表單中止彈出警告以前會看到兩次、三次甚至四次警告。這是怎麼回事呢?原來咱們尚未考慮 HTTP 就緒狀態,這是請求/響應循環中的一個重要部分。
HTTP 就緒狀態
服務器在完成請求以後會在 XMLHttpRequest 的 onreadystatechange 屬性中查找要調用的方法。這是真的,但還不完整。事實上,每當 HTTP 就緒狀態改變時它都會調用該方法。
在 Ajax 應用程序中須要瞭解五種就緒狀態:
·0:請求沒有發出(在調用 open() 以前)。
·1:請求已經創建但尚未發出(調用 send() 以前)。
·2:請求已經發出正在處理之中(這裏一般能夠從響應獲得內容頭部)。
·3:請求已經處理,響應中一般有部分數據可用,可是服務器尚未完成響應。
·4:響應已完成,能夠訪問服務器響應並使用它。
對於 Ajax 編程,須要直接處理的唯一狀態就是就緒狀態 4,它表示服務器響應已經完成,能夠安全地使用響應數據了。
檢查就緒狀態
function updatePage() { if (request.readyState == 4) alert("Server is done!"); }
修改後就能夠保證服務器的處理已經完成。
HTTP 狀態碼
還有一個問題 —— 若是服務器響應請求並完成了處理可是報告了一個錯誤怎麼辦?要知道,服務器端代碼應該明白它是由 Ajax、JSP、普通 HTML 表單或其餘類型的代碼調用的,但只能使用傳統的 Web 專用方法報告信息。而在 Web 世界中,HTTP 代碼能夠處理請求中可能發生的各類問題。
您確定遇到過輸入了錯誤的 URL 請求而獲得 404 錯誤碼的情形,它表示該頁面不存在。這僅僅是 HTTP 請求可以收到的衆多錯誤碼中的一種(完整的狀態碼列表請參閱 參考資料 中的連接)。表示所訪問數據受到保護或者禁止訪問的 403 和 401 也很常見。不管哪一種狀況,這些錯誤碼都是從完成的響應 獲得的。換句話說,服務器履行了請求(即 HTTP 就緒狀態是 4)可是沒有返回客戶機預期的數據。
所以除了就緒狀態外,還須要檢查 HTTP 狀態。咱們指望的狀態碼是 200,它表示一切順利。若是就緒狀態是 4 並且狀態碼是 200,就能夠處理服務器的數據了,並且這些數據應該就是要求的數據(而不是錯誤或者其餘有問題的信息)。所以還要在回調方法中增長狀態檢查
檢查 HTTP 狀態碼
function updatePage() { if (request.readyState == 4) if (request.status == 200) alert("Server is done!"); }
爲了增長更健壯的錯誤處理並儘可能避免過於複雜,能夠增長一兩個狀態碼檢查
function updatePage() { if (request.readyState == 4) if (request.status == 200) alert("Server is done!"); else if (request.status == 404) alert("Request URL does not exist"); else alert("Error: status code is " + request.status); }
如今能夠確保請求已經處理完成(經過就緒狀態),服務器給出了正常的響應(經過狀態碼),最後咱們能夠處理服務器返回的數據了。返回的數據保存在 XMLHttpRequest 對象的 responseText 屬性中。
function updatePage() { if (request.readyState == 4) { if (request.status == 200) { var response = request.responseText.split("|"); document.getElementById("order").value = response[0]; document.getElementById("address").innerHTML = response[1].replace(/\n/g, ""); } else alert("status is " + request.status); } }
獲得 responseText 並使用 JavaScript split() 方法從管道符分開。獲得的數組放到 response 中。
獲得的數組放到 response 中。數組中的第一個值 —— 上一個訂單 —— 用 response[0] 訪問,被設置爲 ID 爲 「order」 的字段的值。第二個值 response[1],即客戶地址,則須要更多一點處理。由於地址中的行用通常的行分隔符(「\n」字符)分隔,代碼中須要用 XHTML 風格的行分隔符 <br /> 來代替。替換過程使用 replace() 函數和正則表達式完成。最後,修改後的文本做爲 HTML 表單 div 中的內部 HTML。結果就是表單忽然用客戶信息更新了
XMLHttpRequest 的另外一個重要屬性 responseXML。若是服務器選擇使用 XML 響應則該屬性包含(也許您已經猜到)XML 響應。處理 XML 響應和處理普通文本有很大不一樣,涉及到解析、文檔對象模型(DOM)和其餘一些問題。