XMLHttpRequest簡介

要真正實現這種絢麗的奇蹟,必須很是熟悉一個 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)和其餘一些問題。

相關文章
相關標籤/搜索