概述

Ajax(Asynchronous JavaScript and XML,即異步 JavaScript 和 XML)技術用于與服務器交換數據并刷新部分頁面,實現(xiàn)更好的用戶體驗。

Ajax 的核心對象是 XMLHttpRequest,通過 XMLHttpRequest 可以在不刷新頁面的情況下請求特定 URL,獲取數據。由微軟實現(xiàn)并在 IE5 中支持,用于執(zhí)行異步網絡請求。雖然 Ajax 是 Asynchronous JavaScript+XML的縮寫,但Ajax通信與數據格式無關,并不一定是XML格式。甚至支持 HTTP 以外的協(xié)議(如 file:// 和 FTP),盡管可能受到更多出于安全等原因的限制。

使用 Ajax 需要幾個步驟:

  1. 創(chuàng)建 XMLHttpRequest 對象。
  2. 發(fā)出 HTTP 請求。
  3. 接收服務器傳回的數據。
  4. 更新網頁數據。

總之,Ajax 就是通過 XMLHttpRequest 對象發(fā)出 HTTP 請求,得到服務器響應并處理。

創(chuàng)建 XMLHttpRequest

在所有現(xiàn)代瀏覽器都可以通過 XMLHttpRequest 構造函數創(chuàng)建對象:

let xhr = new XMLHttpRequest();

而在老版本 IE5 和 IE6 中使用 ActiveX 對象創(chuàng)建:

let xhr = new ActiveXObject("Micro;);

使用 XMLHttpRequest

創(chuàng)建對象后,需要使用 XMLHttpRequest 對象調用 open(type, url, async) 方法并設置三個參數:

  • type:表示請求類型,如 "get" 、"post" 等。
  • url:表示請求的url。
  • async:表示請求是否異步。如 true表示異步請求,false表示同步請求,它會使JavaScript代碼等待服務器響應之后再繼續(xù)執(zhí)行。

請求

XMLHttpRequest 使用 open() 方法初始化一個請求,一共可以接收五個參數:

open(method, url, async, username, password): void;
  • method:字符串,表示要傳入的HTTP方法,如/GET/POST/PUT/DELETE等。
  • url:字符串,表示請求發(fā)送目標URL。
  • async:布爾值,表示請求是否為異步,默認為true。如果值為false,send()方法只有等待收到服務器返回結果,才會進行下一步操作。參數可選。如果 multipart 屬性為 true 則這個必須為 true,否則將引發(fā)異常。注意,主線程上的同步請求很容易破壞用戶體驗,應避免;實際上,許多瀏覽器已完全啟用主線程上的同步XMLHttpRequest支持。在Worker中允許同步請求。
  • username:字符串,表示用戶名用于認證用途,默認為null。參數可選。
  • password:字符串,表示密碼用于認證用途,默認為null。參數可選。

因此,前兩個參數是必須要添加的。請求初始化后,就可以調用send() 方法發(fā)出 HTTP 請求。如果是異步請求(默認異步請求),則此方法會在請求發(fā)送后立即返回;如果是同步請求,則此方法直接響應到達后才會返回。該方法有一個可選參數,作為請求主體,請求方法是GET/HEAD,則請求體設置為null。

send(body): void;

該方法的參數是 XMLHttpRequest 請求中要發(fā)送的數據體,可以設置的值為:

  • Document:發(fā)送 Document 類型的數據,但發(fā)送之前會被序列化。
  • BodyInit:可以是 Blob/BufferSource/FormData/URLSearchParams/ReadableStream<Uint8Array>/string 這幾種類型的數據。
  • null。如果沒有指定值,默認值就是 null。

因此,創(chuàng)建完XMLHttpRequest對象后,就會按順序調用open()和send()方法來發(fā)送請求。而最常用的方法就是 GET 和 POST 方法。

GET

GET 請求方法,主要用于查詢服務器信息。而查詢的參數要正確編碼并添加到URL后面,例如 exam;password=a123456,參數之間會用&符號分隔,然后才能傳給 open() 方法。該方法最常見的錯誤就是格式不對,因此可以使用 encodeURIComponent() 函數對字符串進行編碼。

let url = "exam;; url = addParam(url, "username", "Alpha"); url = addParam(url, "password", "a123456"); x('get', url, true); function addParam(url, name, value) { ? ?url += ("?") == -1 ? "?" : "&"); ? ?url += encodeURIComponent(name) + "=" + encodeURIComponent(value); ? ?return url; }

addParam() 函數保證 XMLHttpRequest 發(fā)送請求的 URL 格式正確。

POST

POST 請求方法,主要用于向服務器發(fā)送數據。POST 請求會在請求體中攜帶要提交的數據。POST 請求在傳參上不用像 GET 請求那樣將參數拼接在 URL 后面,而是使用 send() 方法來攜帶要提交的數據。

默認情況下,對服務器而言,POST 請求與HTML表單提交是不一樣的。服務器邏輯需要讀取原始 POST 數據才能取得瀏覽器發(fā)送的數據。不過,還可以使用 XML 模擬表單提交。為此,第一步需要把 Content-Type 頭部設置為 "application/x-www-formurlencoded",這是提交表單時使用的內容類型。第二步是創(chuàng)建對應格式的字符串。POST 數據此時使用與查詢字符串相同的格式。如果網頁中確實有一個表單需要序列化并通過 XMLHttpRequest 發(fā)送到服務器,則可以使用 serialize() 函數來創(chuàng)建相應的字符串,如下所示:

function submitData() { ? ?let xhr = new XMLHttpRequest(); ? ?x = function() { ? ? ? ?if == 4) { ? ? ? ? ? ?if >= 200 && x < 300) || x == 304) { ? ? ? ? ? ? ? ?con); ? ? ? ? ? } else { ? ? ? ? ? ? ? ?alert("請求失敗: " + x); ? ? ? ? ? } ? ? ? } ? }; ? ?x("post", "exam;, true); ? ?x("Content-Type", "application/x-www-form-urlencoded"); ? ?// ID為 user-info 的表單元素 ? ?let form = document.getElementById("user-info"); ? ?x(serialize(form)); }

注意:POST 請求相比 GET 請求要占用更多資源。從性能方面說,發(fā)送相同數據的數據,GET請求比 POST 請求快兩倍。

響應

當服務器收到請求并響應后,XMLHttpRequest 對象會有以下屬性被填充數據:

  • status:響應的 HTTP 狀態(tài)碼。
  • stautsText:響應的 HTTP 狀態(tài)描述。
  • response:響應的正文。
  • responseText:作為響應體返回的文本。
  • responseXML:如果響應的內容類型是 "text/xml"或"application/xml",那就是包含響應數據的 XML DOM 文檔。

一般都是通過 status 屬性來確保響應是否成功返回。當 status 為 2xx 表示成功,為 304 表示資源未被修改,而是從緩存中取出的。這時的 responseText 或 responseXML 屬性中會有內容。因此,我們可以使用 status 屬性來判斷響應是否有效,如下所示:

x("get", "exam;, false); x(null); if >= 200 && x < 300) || x == 304) { ? ?con); } else { ? ?con("Request was unsuccessful: " + x); }

response

XMLH 屬性返回響應的數據體(即 HTTP 響應的 body 部分)。返回的類型為 ArrayBuffer、Blob、Document、Object或DOMString中的一個。具體類型由 XMLHType 類型決定。

當請求尚未完成或尚未成功,該值為 null。但當 responseType 屬性設置成 "text" 或空字符串("") 且當請求狀態(tài)在LOADING時,response屬性包含到目前為止該請求已經取得的內容。

let xhr = new XMLHttpRequest(); x = function() { ? ?if == 4) { ? ? ? ?con); ? } }

responseType

XMLHType 屬性是一個字符串,返回響應數據的類型。允許手動設置返回數據的類型。如果設置為空字符串,則使用默認的"text"類型。

當 responseType 設置為一個特定的類型時,需確保服務器返回的類型和你所設置的類型是兼容的。如果不兼容,即使服務器返回了數據,數據也會變成null。responseType 屬性支持以下幾種值:

  1. "":當responseType為空字符串時,與 text 相同,表示服務器返回文本數據。
  2. "arraybuffer":表示服務器返回的是一個包含二進制數據的ArrayBuffer 對象。
  3. “blob”:表示服務器返回的是一個包含二進制數據的 Blob對象。
  4. “document”:表示服務器返回的是一個HTML Document 或 XML Document,這取決于接收數據的 MIME 類型。
  5. “json”:表示將接收到的服務器數據視為JSON來進行解析并得到。
  6. “text”:表示服務器返回的是以DOMString對象表示的文本。

上面幾種類型之中,text類型適合大多數情況,而且直接處理文本也比較方便。document類型適合返回HTML/XML文檔的情況,這意味著,對于那些打開 CORS 的網站,可以直接用 Ajax 抓取網頁,然后不用解析 HTML 字符串,直接對抓取回來的數據進行 DOM 操作。blob 類型適合讀取二進制數據,比如圖片文件。XMLHType屬性要在調用 open() 方法之后,并且在調用 send() 方法之前調用。

let xhr = new XMLHttpRequest(); x("GET", "exam;, true); x = "json"; x(null);

readyState

XMLH 屬性返回一個無符號短整型數字,表示XMLHttpRequest對象的當前狀態(tài)。該對象會返回以下某個值:

  • 返回 0,未初始化(Uninitialized),狀態(tài)為 UNSENT。表示代理被創(chuàng)建,但尚未調用 open() 方法。
  • 返回 1,狀態(tài)為 Open 已打開(Open),狀態(tài)為OPENED。表示 open() 方法已被調用,但尚未調用 send() 方法。
  • 返回 2,已發(fā)送(Sent),狀態(tài)為HEADERS_RECEIVED。表示已調用 send() 方法,并且頭部和狀態(tài)已經可獲得,但尚未收到響應。
  • 返回 3:接收中(Receiving),狀態(tài)為LOADING。表示已經收到部分響應。
  • 返回 4:已完成(Complete),狀態(tài)為DONE。表示請求操作已完成。意味著數據傳輸已經徹底完成或失敗。

通信過程中,每當 XMLHttpRequest 對象狀態(tài)發(fā)送變化,readyState 屬性值就會被改變,并會觸發(fā) onreadystatechange事件。并且XMLHttpRequest對象調用abort()方法,終止請求,也會造成 readyState屬性變化。為保證兼容性,onreadystatechange事件應在open()方法之前賦值。如下所示:

let xhr = new XMLHttpRequest(); x = function() { if == 4) { if >= 200 && x < 300) || x == 304) { con); } else { alert("Request was unsuccessful: " + x); } } }; x("get", "exam;, true); x(null);

如果之前使用的是異步請求并想在響應之前取消,可以調用 abort() 方法:

let xhr = new XMLHttpRequest(); x("get", "exam;, true); setTimeout(function() { if (xhr) { x(); xhr = null; } }, 5000); // 5秒后,終止 Ajax 請求

調用這個方法后,XMLHttpRequest 對象會停止觸發(fā)事件,并阻止訪問這個對象上任何與響應相關的屬性,而 readyState 屬性變?yōu)?4,status 屬性變?yōu)?0 。中斷請求后,應該取消對 XMLHttpRequest 對象的引用。由于內存問題,不推薦重用 XMLHttpRequest 對象。

HTTP頭部

在 HTTP 的每次請求和響應中都會攜帶一些頭部字段,默認請求下,XMLHttpRequest 請求會發(fā)送以下頭部字段。

  • Accept:瀏覽器可以處理的內容類型。
  • Accept-Charset:瀏覽器可以顯示的字符集。
  • Accept-Encoding:瀏覽器可以處理的壓縮編碼類型。
  • Accept-Language:瀏覽器使用的語言。
  • Connection:瀏覽器與服務器的連接類型。
  • Cookie:頁面中設置的 Cookie。
  • Host:發(fā)送請求的頁面所在地域。
  • Referer:發(fā)送請求的頁面的 URI。
  • User-Agent:瀏覽器的用戶代理字符串。

XMLHttpRequest對象通過一些方法暴露與請求和響應相關的頭部字段。

setRequestHeader()

XMLH() 方法是設置 HTTP 請求頭部字段的方法。此方法接收兩個參數:第一個參數是頭部屬性名,第二個參數是頭部屬性值。為保證請求頭被發(fā)送,必須在 open() 之后,send() 之前調用。如果多次調用,設置同一個字段的值會合并成單一的值發(fā)送。如下所示:

let xhr = new XMLHttpRequest(); x("get", "exam;, true); x("Content-Type", "application/json"); x("Custom-Header", "Custom-Value"); x(null);

自定義頭部要區(qū)別于瀏覽器正常發(fā)送的頭部,否則會影響服務器正常響應。默認頭部在有些瀏覽器上可以重寫。而自定義一些 header 屬性進行跨域請求時,可能會遇到 "not allowed by Access-Control-Allow-Headers in preflight response",你可能需要在你的服務端設置 “Access-Control-Allow-Headers”。

getResponseHeader()/getAllResponseHeaders()

XMLH() 方法用于返回 HTTP 響應頭中指定的屬性值。如果在返回時,有多個一樣的名字,那么返回的值就是用逗號和空格分隔開的字符串。

而 XMLH() 方法返回所有的響應頭,是以 CRLF 分隔(回車+換行)的字符串,如果沒收到服務器回應,該屬性為 null。以下就是該方法返回的字符串樣子:

Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: * Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE Access-Control-Allow-Origin: * Access-Control-Max-Age: 3600 Content-Length: 0 Content-Type: application/json;charset=UTF-8 Date: Sun, 13 Dec 2020 11:46:23 GMT Server: Apache-Coyote

通過解析以上頭部字段的輸出,就可以知道服務器發(fā)送的所有頭部,而不需要單獨去檢查了。

withCredentials

XMLH 屬性是一個Boolean類型,用來指定跨域請求時,是否應帶有用戶信息(如Cookie和認證的HTTP頭信息)。默認值是 false,即向 發(fā)送跨域請求時,不會發(fā)送 設置在本機上的 Cookie。

當需要跨域 AJAX 請求發(fā)送 Cookie 時,需要設置 XMLH 為 true。同源請求無需設置。而想要這個屬性生效,服務器需要顯示返回 Access-Control-Allow-Credentials 頭信息。

Access-Control-Allow-Credentials: true

注意:腳本總是遵守同源策略,無法從 document.cookie 或者 HTTP 響應的頭信息中讀取跨域的 Cookie,無論 XMLH 的屬性值是true或false。

abort()

XMLH() 方法用于終止已被發(fā)出的請求。當一個請求被終止,readyState 和 status 屬性都會被置為 0。

事件

XMLHttpRequest 對象的事件基本上都和請求進度有關,以下列出與 XMLHttpRequest 對象有關的事件:

  • abort:請求中止時(比如用戶取消)觸發(fā)。如果發(fā)生錯誤導致中止,不會觸發(fā)該事件。
  • error:請求錯誤時觸發(fā)。
  • load:請求成功并完成響應時觸發(fā),不用檢查 readyState 屬性,可替代 readystatechange 事件。
  • loadstart:請求成功時并接收到響應的第一個字節(jié)時觸發(fā)。也適用于 <img> 和 <video 元素。
  • loadend:請求成功并響應完成時,且在 error、abort、load 等事件之后觸發(fā)。
  • progress:在請求接收到數據時候被周期性觸發(fā)。
  • timeout:請求超時時觸發(fā)。

觸發(fā)的先后順序為 loadstart > progress > error/abort/load > loadend。

let xhr = new XMLHttpRequest(); x = function(event) { con("請求開始:" + event); }; x("progress", function(event) { let divStatus = document.getElementById("status"); divS = event.lengthComputable; if ) { divS = divS + "\n" + "Received " + event.position + " of " + event.total + " bytes"; } }, false); x = function() { con("請求中止"); }; x = function(event) { if >= 200 && x < 300) || x === 304) { con); } else { con("請求失?。?#34; + x); } }; x = function(event) { con("請求錯誤:" + event); }; xend = function(event) { con("請求完成:" + event); }; x = function() { con("請求超時。"); }; x("get", "http://localhost:8088/servlets/ajaxGet", true); x = 5000; // 5秒超時 x(null); setTimeout(function () { if (xhr) { x(); xhr = null; } }, 4000); // 4 秒之后,終止AJAX請求

其中,progress 事件觸發(fā)會收到 event 對象,該屬性包含 lengthComputable、position 和 totalSize 這三個屬性:

  • lengthComputable:布爾值屬性,表示進度信息是否可用。
  • position:接收的字節(jié)數。
  • total:響應的 Content-Length 頭部定義的總字節(jié)數。

進度事件

進度事件定義了客戶端/服務端通信,用于測量如 HTTP 請求(XMLHttpRequest或<img>、<audio>、<video>、<style>、<link>等底層資源的加載)等底層流程進度的事件。繼承于 Event。原生提供ProgressEvent()構造函數生成事件對象。如下所示:

ProgressEvent(type, {lengthComputable: boolean, loaded: number, total: number});

構造函數中有兩個參數:

  • 第一個參數返回的是字符串,表示事件的類型,這個參數是必須的。
  • 第二個參數是配置對象,表示事件的屬性,該參數可選。除了繼承 Event 接口的配置屬性外,還可以是下面的屬性,屬性可選。lengthComputable:布爾值,表示加載的總量是否可以計算,默認是 false。loaded:整數,表示已經加載的量,默認是 0。total:整數,表示需要加載的總量,默認是 0。

進度相關的事件都是繼承自 ProgressEvent 接口的,該接口用來描述外部資源加載的進度。而瀏覽器原生提供 ProgressEvent() 構造函數來生成事件實例。如下所示:

let event = new ProgressEvent(type, options);

而構造函數中接收的兩個參數:第一個參數是字符串,表示事件的類型,這個參數是必須的;第二個參數是配置對象,表示事件的屬性,該參數可選。配置對象除了可以使用 Event 接口的配置屬性,還可以使用下面的屬性,所有這些屬性都是可選的。

  • lengthComputable:布爾值,表示加載的總量是否可以計算,默認是 false。
  • loaded:整數,表示已經加載的量,默認是 0。
  • total:整數,表示需要加載的總量,默認是 0。

屬性

ProgressEvent 除了從 Event 繼承的屬性與方法外,還有三個與構造函數中對應的三個屬性。

  • Progre:只讀屬性,是一個 Boolean 標志,指示基礎流程是否可以計算總工作量和已經完成的工作量。換句話說,它告訴進度是否可測量。
  • Progre:只讀屬性,表示一個 unsigned long long,代表基礎流程已經完成的工作量??梢酝ㄟ^屬性和 Progre 來計算完成的工作量。使用 HTTP 下載資源時,這僅代表內容本身的一部分,而不代表頭和其它開銷。
  • Progre:只讀屬性,表示一個 unsigned long long,表示基礎流程正在執(zhí)行的工作總量。使用 HTTP 下載資源時,這僅代表內容本身,而不代表頭和其它開銷。

如果 Progre 為 false,Progre 實際上是沒有意義的。

XMLHttpRequest Level 2

XMLHttpRequest Level 2 是在 XMLHttpRequest Level 1 的基礎上進一步的擴展。但并非所有瀏覽器都實現(xiàn)了 XMLHttpRequest Level 2 的所有功能,也可能只實現(xiàn)了部分功能。

FormData

在 XMLHttpRequest Level 2 中新增了 FormData 類型,主要用于將數據編譯成鍵值對,使用XMLHttpRequest來發(fā)送數據。也用于創(chuàng)建與表單類似格式的數據。創(chuàng)建一個FormData對象,如下所示:

let data = new FormData(); da("username", "Clark"); da("account", "addie"); let request = new XMLHttpRequest(): reque("post", ";); reque(data);

append() 方法接收兩個參數:鍵,相當于表單字段名;值,相當于表單字段名的值。當然,也可以直接給 FormData 構造函數傳入表單元素,也可以將表單中的數據作為鍵值對填充進去,也可以附加額外的數據到FormData對象中:

let form = document.querySelector("form"); let data = new FormData(form); da("serialnumber", 134);

而使用 FormData之后,可以不再需要給 XMLHttpRequest對象顯式地設置任何請求頭部。XMLHttpRequest對象能夠識別作為 FormData對象傳入的數據類型并自動配置相應的頭部。

timeout

XMLH 屬性是一個表示發(fā)送數據后等待的毫秒數的一個整數,響應請求時間超出該屬性設置的毫秒數,就會中斷該請求。IE8 給 XMLHttpRequest 添加了該屬性,并在 XMLHttpRequest Level 2 中添加了該特性。默認值為 0,當超時時,就會觸發(fā) timeout 事件。如下所示:

let xhr = new XMLHttpRequest(); x = function() { if === 4) { if >= 200 && x < 300) || x === 304) { con); } else { con("請求失?。?#34; + x); } } }; x = function() { con("請求超時。" ); }; x("get", "http://localhost:8088/servlets/ajaxGet", true); x = 1000; // 1秒超時 x(null);

上面的例子演示了設置超時timout屬性值,超時后請求中斷觸發(fā)ontimeout事件,并將 status 屬性值置 0。但readyState屬性值仍為 4,因此也會調用onreadystatechange 事件。

upload

XMLH 屬性會返回一個 XMLHttpRequestUpload 對象,代表上傳進度。這個對象不透明,但作為一個 XMLHttpRequestEventTarget,可以通過對其綁定事件來追蹤它的進度。

XMLH 屬性可以監(jiān)聽 loadstart/progress/abort/error/load/timeout/loadend 這幾種事件。

<body> <progress id="uploadprogress" min="0" max="100" value="0">0</progress> <br> <input type="file" id="upload_files" /> <br> <button onclick="upload()">上傳</button> </body> <script> function upload() { let resource = document.getElementsByTagName('input')[0].files[0]; // 此處進行 ajax 上傳 let xhr = new XMLHttpRequest(); // 預置的 formdata 對象,詳情查看 ajax level 2, let data = new FormData(); da("resource", resource); x("post", "http://localhost:8088/servlets/upload"); x = function() { if (x === 200) { con("上傳成功"); } else { con("上傳出錯"); } }; x = function(e) { con('An error occurred while submitting the form. Maybe your file is too big'); }; // 上傳進度事件 x('progress', function (ev) { if ) { let complete = / ev.total * 100 | 0); let progress = document.getElementById('uploadprogress'); = complete; } }); x(data); } </script>

當進行上傳操作時,如果要跨域上傳,需要在服務器設置 CORS。

跨源資源共享(CORS,Cross-Origin Resource Sharing)定義瀏覽器與服務器如何實現(xiàn)跨源通信。使得 XMLHttpRequest 請求克服了同源使用的限制。簡單的授權訪問,在服務器設置請求頭:

Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE Access-Control-Max-Age: 3600 Access-Control-Allow-Headers: Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers

overrideMimeType()

XMLH() 方法用來重寫 XMLHttpRequest 響應的 MIME 類型。是 Firefox 首次引入,在 XMLHttpRequest Level 2 中添加了該方法。因為響應返回的 MIME 類型決定了 XMLHttpRequest 對象如何處理響應。例如服務器實際發(fā)送的是 XML數據,但響應頭中MIME類型設置的是text/plain,瀏覽器不會自動解析,responseXML屬性值是null。此時調用overrideMimeType() 可以保證將響應當成 XML 而不是純文本來處理:

let xhr = new XMLHttpRequest(); x("get", "exam;, true); x("text/xml"); x(null);

注意:為了正確覆蓋響應的 MIME 類型,該方法必須在 send() 方法之前調用。

小結

Ajax 是無需刷新當前頁面即可從服務器獲取數據的一種方法,其中核心對象是 XMLHttpRequest,最早由微軟發(fā)明,并在 IE5 中引入。之后,其它瀏覽器都實現(xiàn)了該對象。W3C 雖然也引入了 Web 標準。雖然不同瀏覽器有些差異,但基本使用是相對較規(guī)范的,因此可以放心使用。

1.《(如何終止ajax請求)如何取消ajax請求》援引自互聯(lián)網,旨在傳遞更多網絡信息知識,僅代表作者本人觀點,與本網站無關,侵刪請聯(lián)系頁腳下方聯(lián)系方式。

2.《(如何終止ajax請求)如何取消ajax請求》僅供讀者參考,本網站未對該內容進行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。

3.文章轉載時請保留本站內容來源地址,http://f99ss.com/keji/3228190.html