亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

面試必備之a(chǎn)jax原始請求

瀏覽:237日期:2022-06-12 10:28:42
目錄
  • XMLHttpRequest 對象
    • 簡介
    • XMLHttpRequest 的實例屬性
      • XMLHttpRequest.readyState
      • XMLHttpRequest.onreadystatechange
      • XMLHttpRequest.response
      • XMLHttpRequest.responseType
      • XMLHttpRequest.responseText
      • XMLHttpRequest.responseXML
      • XMLHttpRequest.responseURL
      • XMLHttpRequest.status,XMLHttpRequest.statusText
      • XMLHttpRequest.timeout,XMLHttpRequestEventTarget.ontimeout
      • 事件監(jiān)聽屬性
      • XMLHttpRequest.withCredentials
      • XMLHttpRequest.upload
    • XMLHttpRequest 的實例方法
      • XMLHttpRequest.open()
      • XMLHttpRequest.send()
      • XMLHttpRequest.setRequestHeader()
      • XMLHttpRequest.overrideMimeType()
      • XMLHttpRequest.getResponseHeader()
      • XMLHttpRequest.getAllResponseHeaders()
      • XMLHttpRequest.abort()
    • XMLHttpRequest 實例的事件
      • readyStateChange 事件
      • progress 事件
      • load 事件、error 事件、abort 事件
      • loadend 事件
      • timeout 事件
    • Navigator.sendBeacon()
    • 總結(jié)

      XMLHttpRequest 對象

      簡介

      瀏覽器與服務(wù)器之間,采用 HTTP 協(xié)議通信。用戶在瀏覽器地址欄鍵入一個網(wǎng)址,或者通過網(wǎng)頁表單向服務(wù)器提交內(nèi)容,這時瀏覽器就會向服務(wù)器發(fā)出 HTTP 請求。

      1999年,微軟公司發(fā)布 IE 瀏覽器5.0版,第一次引入新功能:允許 JavaScript 腳本向服務(wù)器發(fā)起 HTTP 請求。這個功能當時并沒有引起注意,直到2004年 Gmail 發(fā)布和2005年 Google Map 發(fā)布,才引起廣泛重視。2005年2月,AJAX 這個詞第一次正式提出,它是 Asynchronous JavaScript and XML 的縮寫,指的是通過 JavaScript 的異步通信,從服務(wù)器獲取 XML 文檔從中提取數(shù)據(jù),再更新當前網(wǎng)頁的對應(yīng)部分,而不用刷新整個網(wǎng)頁。后來,AJAX 這個詞就成為 JavaScript 腳本發(fā)起 HTTP 通信的代名詞,也就是說,只要用腳本發(fā)起通信,就可以叫做 AJAX 通信。W3C 也在2006年發(fā)布了它的國際標準。

      具體來說,AJAX 包括以下幾個步驟。

      1. 創(chuàng)建 XMLHttpRequest 實例
      2. 發(fā)出 HTTP 請求
      3. 接收服務(wù)器傳回的數(shù)據(jù)
      4. 更新網(wǎng)頁數(shù)據(jù)

      概括起來,就是一句話,AJAX 通過原生的XMLHttpRequest對象發(fā)出 HTTP 請求,得到服務(wù)器返回的數(shù)據(jù)后,再進行處理。現(xiàn)在,服務(wù)器返回的都是 JSON 格式的數(shù)據(jù),XML 格式已經(jīng)過時了,但是 AJAX 這個名字已經(jīng)成了一個通用名詞,字面含義已經(jīng)消失了。

      XMLHttpRequest對象是 AJAX 的主要接口,用于瀏覽器與服務(wù)器之間的通信。盡管名字里面有XML和Http,它實際上可以使用多種協(xié)議(比如file或ftp),發(fā)送任何格式的數(shù)據(jù)(包括字符串和二進制)。

      XMLHttpRequest本身是一個構(gòu)造函數(shù),可以使用new命令生成實例。它沒有任何參數(shù)。

      var xhr = new XMLHttpRequest();
      

      一旦新建實例,就可以使用open()方法指定建立 HTTP 連接的一些細節(jié)。

      xhr.open("GET", "http://www.example.com/page.php", true);
      

      上面代碼指定使用 GET 方法,跟指定的服務(wù)器網(wǎng)址建立連接。第三個參數(shù)true,表示請求是異步的。

      然后,指定回調(diào)函數(shù),監(jiān)聽通信狀態(tài)(readyState屬性)的變化。

      xhr.onreadystatechange = handleStateChange;
      
      function handleStateChange() {
        // ...
      }
      

      上面代碼中,一旦XMLHttpRequest實例的狀態(tài)發(fā)生變化,就會調(diào)用監(jiān)聽函數(shù)handleStateChange

      最后使用send()方法,實際發(fā)出請求。

      xhr.send(null);
      

      上面代碼中,send()的參數(shù)為null,表示發(fā)送請求的時候,不帶有數(shù)據(jù)體。如果發(fā)送的是 POST 請求,這里就需要指定數(shù)據(jù)體。

      一旦拿到服務(wù)器返回的數(shù)據(jù),AJAX 不會刷新整個網(wǎng)頁,而是只更新網(wǎng)頁里面的相關(guān)部分,從而不打斷用戶正在做的事情。

      注意,AJAX 只能向同源網(wǎng)址(協(xié)議、域名、端口都相同)發(fā)出 HTTP 請求,如果發(fā)出跨域請求,就會報錯(詳見《同源政策》和《CORS 通信》兩章)。

      下面是XMLHttpRequest對象簡單用法的完整例子。

      var xhr = new XMLHttpRequest();
      
      xhr.onreadystatechange = function(){
        // 通信成功時,狀態(tài)值為4
        if (xhr.readyState === 4){
          if (xhr.status === 200){
            console.log(xhr.responseText);
          } else {
            console.error(xhr.statusText);
          }
        }
      };
      
      xhr.onerror = function (e) {
        console.error(xhr.statusText);
      };
      
      xhr.open("GET", "/endpoint", true);
      xhr.send(null);
      

      XMLHttpRequest 的實例屬性

      XMLHttpRequest.readyState

      XMLHttpRequest.readyState返回一個整數(shù),表示實例對象的當前狀態(tài)。該屬性只讀。它可能返回以下值。

      0,表示 XMLHttpRequest 實例已經(jīng)生成,但是實例的open()方法還沒有被調(diào)用。

      1,表示open()方法已經(jīng)調(diào)用,但是實例的send()方法還沒有調(diào)用,仍然可以使用實例的setRequestHeader()方法,設(shè)定 HTTP 請求的頭信息。

      2,表示實例的send()方法已經(jīng)調(diào)用,并且服務(wù)器返回的頭信息和狀態(tài)碼已經(jīng)收到。

      3,表示正在接收服務(wù)器傳來的數(shù)據(jù)體(body 部分)。這時,如果實例的responseType屬性等于text或者空字符串,responseText屬性就會包含已經(jīng)收到的部分信息。

      4,表示服務(wù)器返回的數(shù)據(jù)已經(jīng)完全接收,或者本次接收已經(jīng)失敗。

      通信過程中,每當實例對象發(fā)生狀態(tài)變化,它的readyState屬性的值就會改變。這個值每一次變化,都會觸發(fā)readyStateChange事件。

      var xhr = new XMLHttpRequest();
      
      if (xhr.readyState === 4) {
      ??// 請求結(jié)束,處理服務(wù)器返回的數(shù)據(jù)
      } else {
      ? // 顯示提示“加載中……”
      }
      

      上面代碼中,xhr.readyState等于4時,表明腳本發(fā)出的 HTTP 請求已經(jīng)完成。其他情況,都表示 HTTP 請求還在進行中。

      XMLHttpRequest.onreadystatechange

      XMLHttpRequest.onreadystatechange屬性指向一個監(jiān)聽函數(shù)。readystatechange事件發(fā)生時(實例的readyState屬性變化),就會執(zhí)行這個屬性。

      另外,如果使用實例的abort()方法,終止 XMLHttpRequest 請求,也會造成readyState屬性變化,導(dǎo)致調(diào)用XMLHttpRequest.onreadystatechange屬性。

      下面是一個例子。

      var xhr = new XMLHttpRequest();
      xhr.open( "GET", "http://example.com" , true );
      xhr.onreadystatechange = function () {
        if (xhr.readyState !== 4 || xhr.status !== 200) {
          return;
        }
        console.log(xhr.responseText);
      };
      xhr.send();
      

      XMLHttpRequest.response

      XMLHttpRequest.response屬性表示服務(wù)器返回的數(shù)據(jù)體(即 HTTP 回應(yīng)的 body 部分)。它可能是任何數(shù)據(jù)類型,比如字符串、對象、二進制對象等等,具體的類型由XMLHttpRequest.responseType屬性決定。XMLHttpRequest.response屬性是只讀的。

      如果本次請求沒有成功或者數(shù)據(jù)不完整,該屬性等于null。但是,如果responseType屬性等于text或空字符串,在請求沒有結(jié)束之前(readyState等于3的階段),response屬性包含服務(wù)器已經(jīng)返回的部分數(shù)據(jù)。

      var xhr = new XMLHttpRequest();
      
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          handler(xhr.response);
        }
      }
      

      XMLHttpRequest.responseType

      XMLHttpRequest.responseType屬性是一個字符串,表示服務(wù)器返回數(shù)據(jù)的類型。這個屬性是可寫的,可以在調(diào)用open()方法之后、調(diào)用send()方法之前,設(shè)置這個屬性的值,告訴瀏覽器如何解讀返回的數(shù)據(jù)。如果responseType設(shè)為空字符串,就等同于默認值text。

      XMLHttpRequest.responseType屬性可以等于以下值。

      • ""(空字符串):等同于text,表示服務(wù)器返回文本數(shù)據(jù)。
      • "arraybuffer":ArrayBuffer 對象,表示服務(wù)器返回二進制數(shù)組。
      • "blob":Blob 對象,表示服務(wù)器返回二進制對象。
      • "document":Document 對象,表示服務(wù)器返回一個文檔對象。
      • "json":JSON 對象。
      • "text":字符串。

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

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "/path/to/image.png", true);
      xhr.responseType = "blob";
      
      xhr.onload = function(e) {
        if (this.status === 200) {
          var blob = new Blob([xhr.response], {type: "image/png"});
          // 或者
          var blob = xhr.response;
        }
      };
      
      xhr.send();
      

      如果將這個屬性設(shè)為ArrayBuffer,就可以按照數(shù)組的方式處理二進制數(shù)據(jù)。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "/path/to/image.png", true);
      xhr.responseType = "arraybuffer";
      
      xhr.onload = function(e) {
        var uInt8Array = new Uint8Array(this.response);
        for (var i = 0, len = uInt8Array.length; i < len; ++i) {
          // var byte = uInt8Array[i];
        }
      };
      
      xhr.send();
      

      如果將這個屬性設(shè)為json,瀏覽器就會自動對返回數(shù)據(jù)調(diào)用JSON.parse()方法。也就是說,從xhr.response屬性(注意,不是xhr.responseText屬性)得到的不是文本,而是一個 JSON 對象。

      XMLHttpRequest.responseText

      XMLHttpRequest.responseText屬性返回從服務(wù)器接收到的字符串,該屬性為只讀。只有 HTTP 請求完成接收以后,該屬性才會包含完整的數(shù)據(jù)。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "/server", true);
      
      xhr.responseType = "text";
      xhr.onload = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.responseText);
        }
      };
      
      xhr.send(null);
      

      XMLHttpRequest.responseXML

      XMLHttpRequest.responseXML屬性返回從服務(wù)器接收到的 HTML 或 XML 文檔對象,該屬性為只讀。如果本次請求沒有成功,或者收到的數(shù)據(jù)不能被解析為 XML 或 HTML,該屬性等于null。

      該屬性生效的前提是 HTTP 回應(yīng)的Content-Type頭信息等于text/xml或application/xml。這要求在發(fā)送請求前,XMLHttpRequest.responseType屬性要設(shè)為document。如果 HTTP 回應(yīng)的Content-Type頭信息不等于text/xml和application/xml,但是想從responseXML拿到數(shù)據(jù)(即把數(shù)據(jù)按照 DOM 格式解析),那么需要手動調(diào)用XMLHttpRequest.overrideMimeType()方法,強制進行 XML 解析。

      該屬性得到的數(shù)據(jù),是直接解析后的文檔 DOM 樹。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "/server", true);
      
      xhr.responseType = "document";
      xhr.overrideMimeType("text/xml");
      
      xhr.onload = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.responseXML);
        }
      };
      
      xhr.send(null);
      

      XMLHttpRequest.responseURL

      XMLHttpRequest.responseURL屬性是字符串,表示發(fā)送數(shù)據(jù)的服務(wù)器的網(wǎng)址。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "http://example.com/test", true);
      xhr.onload = function () {
        // 返回 http://example.com/test
        console.log(xhr.responseURL);
      };
      xhr.send(null);
      

      注意,這個屬性的值與open()方法指定的請求網(wǎng)址不一定相同。如果服務(wù)器端發(fā)生跳轉(zhuǎn),這個屬性返回最后實際返回數(shù)據(jù)的網(wǎng)址。另外,如果原始 URL 包括錨點(fragment),該屬性會把錨點剝離。

      XMLHttpRequest.status,XMLHttpRequest.statusText

      XMLHttpRequest.status屬性返回一個整數(shù),表示服務(wù)器回應(yīng)的 HTTP 狀態(tài)碼。一般來說,如果通信成功的話,這個狀態(tài)碼是200;如果服務(wù)器沒有返回狀態(tài)碼,那么這個屬性默認是200。請求發(fā)出之前,該屬性為0。該屬性只讀。

      • 200, OK,訪問正常
      • 301, Moved Permanently,永久移動
      • 302, Moved temporarily,暫時移動
      • 304, Not Modified,未修改
      • 307, Temporary Redirect,暫時重定向
      • 401, Unauthorized,未授權(quán)
      • 403, Forbidden,禁止訪問
      • 404, Not Found,未發(fā)現(xiàn)指定網(wǎng)址
      • 500, Internal Server Error,服務(wù)器發(fā)生錯誤

      基本上,只有2xx和304的狀態(tài)碼,表示服務(wù)器返回是正常狀態(tài)。

      if (xhr.readyState === 4) {
      ??if ( (xhr.status >= 200 && xhr.status < 300)
      ????|| (xhr.status === 304) ) {
      ????// 處理服務(wù)器的返回數(shù)據(jù)
      ??} else {
      ????// 出錯
      ??}
      }
      

      XMLHttpRequest.statusText屬性返回一個字符串,表示服務(wù)器發(fā)送的狀態(tài)提示。不同于status屬性,該屬性包含整個狀態(tài)信息,比如“OK”和“Not Found”。在請求發(fā)送之前(即調(diào)用open()方法之前),該屬性的值是空字符串;如果服務(wù)器沒有返回狀態(tài)提示,該屬性的值默認為“OK”。該屬性為只讀屬性。

      XMLHttpRequest.timeout,XMLHttpRequestEventTarget.ontimeout

      XMLHttpRequest.timeout屬性返回一個整數(shù),表示多少毫秒后,如果請求仍然沒有得到結(jié)果,就會自動終止。如果該屬性等于0,就表示沒有時間限制。

      XMLHttpRequestEventTarget.ontimeout屬性用于設(shè)置一個監(jiān)聽函數(shù),如果發(fā)生 timeout 事件,就會執(zhí)行這個監(jiān)聽函數(shù)。

      下面是一個例子。

      var xhr = new XMLHttpRequest();
      var url = "/server";
      
      xhr.ontimeout = function () {
        console.error("The request for " + url + " timed out.");
      };
      
      xhr.onload = function() {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            // 處理服務(wù)器返回的數(shù)據(jù)
          } else {
            console.error(xhr.statusText);
          }
        }
      };
      
      xhr.open("GET", url, true);
      // 指定 10 秒鐘超時
      xhr.timeout = 10 * 1000;
      xhr.send(null);
      

      事件監(jiān)聽屬性

      XMLHttpRequest 對象可以對以下事件指定監(jiān)聽函數(shù)。

      • XMLHttpRequest.onloadstart:loadstart 事件(HTTP 請求發(fā)出)的監(jiān)聽函數(shù)
      • XMLHttpRequest.onprogress:progress事件(正在發(fā)送和加載數(shù)據(jù))的監(jiān)聽函數(shù)
      • XMLHttpRequest.onabort:abort 事件(請求中止,比如用戶調(diào)用了abort()方法)的監(jiān)聽函數(shù)
      • XMLHttpRequest.onerror:error 事件(請求失敗)的監(jiān)聽函數(shù)
      • XMLHttpRequest.onload:load 事件(請求成功完成)的監(jiān)聽函數(shù)
      • XMLHttpRequest.ontimeout:timeout 事件(用戶指定的時限超過了,請求還未完成)的監(jiān)聽函數(shù)
      • XMLHttpRequest.onloadend:loadend 事件(請求完成,不管成功或失敗)的監(jiān)聽函數(shù)

      下面是一個例子。

      xhr.onload = function() {
       var responseText = xhr.responseText;
       console.log(responseText);
       // process the response.
      };
      
      xhr.onabort = function () {
        console.log("The request was aborted");
      };
      
      xhr.onprogress = function (event) {
        console.log(event.loaded);
        console.log(event.total);
      };
      
      xhr.onerror = function() {
        console.log("There was an error!");
      };
      

      progress事件的監(jiān)聽函數(shù)有一個事件對象參數(shù),該對象有三個屬性:loaded屬性返回已經(jīng)傳輸?shù)臄?shù)據(jù)量,total屬性返回總的數(shù)據(jù)量,lengthComputable屬性返回一個布爾值,表示加載的進度是否可以計算。所有這些監(jiān)聽函數(shù)里面,只有progress事件的監(jiān)聽函數(shù)有參數(shù),其他函數(shù)都沒有參數(shù)。

      注意,如果發(fā)生網(wǎng)絡(luò)錯誤(比如服務(wù)器無法連通),onerror事件無法獲取報錯信息。也就是說,可能沒有錯誤對象,所以這樣只能顯示報錯的提示。

      XMLHttpRequest.withCredentials

      XMLHttpRequest.withCredentials屬性是一個布爾值,表示跨域請求時,用戶信息(比如 Cookie 和認證的 HTTP 頭信息)是否會包含在請求之中,默認為false,即向example.com發(fā)出跨域請求時,不會發(fā)送example.com設(shè)置在本機上的 Cookie(如果有的話)。

      如果需要跨域 AJAX 請求發(fā)送 Cookie,需要withCredentials屬性設(shè)為true。注意,同源的請求不需要設(shè)置這個屬性。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "http://example.com/", true);
      xhr.withCredentials = true;
      xhr.send(null);
      

      為了讓這個屬性生效,服務(wù)器必須顯式返回Access-Control-Allow-Credentials這個頭信息。

      Access-Control-Allow-Credentials: true
      

      withCredentials屬性打開的話,跨域請求不僅會發(fā)送 Cookie,還會設(shè)置遠程主機指定的 Cookie。反之也成立,如果withCredentials屬性沒有打開,那么跨域的 AJAX 請求即使明確要求瀏覽器設(shè)置 Cookie,瀏覽器也會忽略。

      注意,腳本總是遵守同源政策,無法從document.cookie或者 HTTP 回應(yīng)的頭信息之中,讀取跨域的 Cookie,withCredentials屬性不影響這一點。

      XMLHttpRequest.upload

      XMLHttpRequest 不僅可以發(fā)送請求,還可以發(fā)送文件,這就是 AJAX 文件上傳。發(fā)送文件以后,通過XMLHttpRequest.upload屬性可以得到一個對象,通過觀察這個對象,可以得知上傳的進展。主要方法就是監(jiān)聽這個對象的各種事件:loadstart、loadend、load、abort、error、progress、timeout。

      假定網(wǎng)頁上有一個<progress>元素。

      <progress min="0" max="100" value="0">0% complete</progress>
      

      文件上傳時,對upload屬性指定progress事件的監(jiān)聽函數(shù),即可獲得上傳的進度。

      function upload(blobOrFile) {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "/server", true);
        xhr.onload = function (e) {};
      
        var progressBar = document.querySelector("progress");
        xhr.upload.onprogress = function (e) {
          if (e.lengthComputable) {
            progressBar.value = (e.loaded / e.total) * 100;
            // 兼容不支持 <progress> 元素的老式瀏覽器
            progressBar.textContent = progressBar.value;
          }
        };
      
        xhr.send(blobOrFile);
      }
      
      upload(new Blob(["hello world"], {type: "text/plain"}));
      

      XMLHttpRequest 的實例方法

      XMLHttpRequest.open()

      XMLHttpRequest.open()方法用于指定 HTTP 請求的參數(shù),或者說初始化 XMLHttpRequest 實例對象。它一共可以接受五個參數(shù)。

      void open(
         string method,
         string url,
         optional boolean async,
         optional string user,
         optional string password
      );
      
      • method:表示 HTTP 動詞方法,比如GET、POST、PUT、DELETE、HEAD等。
      • url: 表示請求發(fā)送目標 URL。
      • async: 布爾值,表示請求是否為異步,默認為true。如果設(shè)為false,則send()方法只有等到收到服務(wù)器返回了結(jié)果,才會進行下一步操作。該參數(shù)可選。由于同步 AJAX 請求會造成瀏覽器失去響應(yīng),許多瀏覽器已經(jīng)禁止在主線程使用,只允許 Worker 里面使用。所以,這個參數(shù)輕易不應(yīng)該設(shè)為false。
      • user:表示用于認證的用戶名,默認為空字符串。該參數(shù)可選。
      • password:表示用于認證的密碼,默認為空字符串。該參數(shù)可選。

      注意,如果對使用過open()方法的 AJAX 請求,再次使用這個方法,等同于調(diào)用abort(),即終止請求。

      下面發(fā)送 POST 請求的例子。

      var xhr = new XMLHttpRequest();
      xhr.open("POST", encodeURI("someURL"));
      

      XMLHttpRequest.send()

      XMLHttpRequest.send()方法用于實際發(fā)出 HTTP 請求。它的參數(shù)是可選的,如果不帶參數(shù),就表示 HTTP 請求只有一個 URL,沒有數(shù)據(jù)體,典型例子就是 GET 請求;如果帶有參數(shù),就表示除了頭信息,還帶有包含具體數(shù)據(jù)的信息體,典型例子就是 POST 請求。

      下面是 GET 請求的例子。

      var xhr = new XMLHttpRequest();
      xhr.open("GET",
        "http://www.example.com/?id=" + encodeURIComponent(id),
        true
      );
      xhr.send(null);
      

      上面代碼中,GET請求的參數(shù),作為查詢字符串附加在 URL 后面。

      下面是發(fā)送 POST 請求的例子。

      var xhr = new XMLHttpRequest();
      var data = "email="
        + encodeURIComponent(email)
        + "&password="
        + encodeURIComponent(password);
      
      xhr.open("POST", "http://www.example.com", true);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send(data);
      

      注意,所有 XMLHttpRequest 的監(jiān)聽事件,都必須在send()方法調(diào)用之前設(shè)定。

      send方法的參數(shù)就是發(fā)送的數(shù)據(jù)。多種格式的數(shù)據(jù),都可以作為它的參數(shù)。

      void send();
      void send(ArrayBufferView data);
      void send(Blob data);
      void send(Document data);
      void send(String data);
      void send(FormData data);
      

      如果send()發(fā)送 DOM 對象,在發(fā)送之前,數(shù)據(jù)會先被串行化。如果發(fā)送二進制數(shù)據(jù),最好是發(fā)送ArrayBufferView或Blob對象,這使得通過 Ajax 上傳文件成為可能。

      下面是發(fā)送表單數(shù)據(jù)的例子。FormData對象可以用于構(gòu)造表單數(shù)據(jù)。

      var formData = new FormData();
      
      formData.append("username", "張三");
      formData.append("email", "[email protected]");
      formData.append("birthDate", 1940);
      
      var xhr = new XMLHttpRequest();
      xhr.open("POST", "/register");
      xhr.send(formData);
      

      上面代碼中,F(xiàn)ormData對象構(gòu)造了表單數(shù)據(jù),然后使用send()方法發(fā)送。它的效果與發(fā)送下面的表單數(shù)據(jù)是一樣的。

      <form id="registration" name="registration" action="/register">
        <input type="text" name="username" value="張三">
        <input type="email" name="email" value="[email protected]">
        <input type="number" name="birthDate" value="1940">
        <input type="submit" onclick="return sendForm(this.form);">
      </form>
      

      下面的例子是使用FormData對象加工表單數(shù)據(jù),然后再發(fā)送。

      function sendForm(form) {
        var formData = new FormData(form);
        formData.append("csrf", "e69a18d7db1286040586e6da1950128c");
      
        var xhr = new XMLHttpRequest();
        xhr.open("POST", form.action, true);
        xhr.onload = function() {
          // ...
        };
        xhr.send(formData);
      
        return false;
      }
      
      var form = document.querySelector("#registration");
      sendForm(form);
      

      XMLHttpRequest.setRequestHeader()

      XMLHttpRequest.setRequestHeader()方法用于設(shè)置瀏覽器發(fā)送的 HTTP 請求的頭信息。該方法必須在open()之后、send()之前調(diào)用。如果該方法多次調(diào)用,設(shè)定同一個字段,則每一次調(diào)用的值會被合并成一個單一的值發(fā)送。

      該方法接受兩個參數(shù)。第一個參數(shù)是字符串,表示頭信息的字段名,第二個參數(shù)是字段值。

      xhr.setRequestHeader("Content-Type", "application/json");
      xhr.setRequestHeader("Content-Length", JSON.stringify(data).length);
      xhr.send(JSON.stringify(data));
      

      上面代碼首先設(shè)置頭信息Content-Type,表示發(fā)送 JSON 格式的數(shù)據(jù);然后設(shè)置Content-Length,表示數(shù)據(jù)長度;最后發(fā)送 JSON 數(shù)據(jù)。

      XMLHttpRequest.overrideMimeType()

      XMLHttpRequest.overrideMimeType()方法用來指定 MIME 類型,覆蓋服務(wù)器返回的真正的 MIME 類型,從而讓瀏覽器進行不一樣的處理。舉例來說,服務(wù)器返回的數(shù)據(jù)類型是text/xml,由于種種原因瀏覽器解析不成功報錯,這時就拿不到數(shù)據(jù)了。為了拿到原始數(shù)據(jù),我們可以把 MIME 類型改成text/plain,這樣瀏覽器就不會去自動解析,從而我們就可以拿到原始文本了。

      xhr.overrideMimeType("text/plain")
      

      注意,該方法必須在send()方法之前調(diào)用。

      修改服務(wù)器返回的數(shù)據(jù)類型,不是正常情況下應(yīng)該采取的方法。如果希望服務(wù)器返回指定的數(shù)據(jù)類型,可以用responseType屬性告訴服務(wù)器,就像下面的例子。只有在服務(wù)器無法返回某種數(shù)據(jù)類型時,才使用overrideMimeType()方法。

      var xhr = new XMLHttpRequest();
      xhr.onload = function(e) {
        var arraybuffer = xhr.response;
        // ...
      }
      xhr.open("GET", url);
      xhr.responseType = "arraybuffer";
      xhr.send();
      

      XMLHttpRequest.getResponseHeader()

      XMLHttpRequest.getResponseHeader()方法返回 HTTP 頭信息指定字段的值,如果還沒有收到服務(wù)器回應(yīng)或者指定字段不存在,返回null。該方法的參數(shù)不區(qū)分大小寫。

      function getHeaderTime() {
        console.log(this.getResponseHeader("Last-Modified"));
      }
      
      var xhr = new XMLHttpRequest();
      xhr.open("HEAD", "yourpage.html");
      xhr.onload = getHeaderTime;
      xhr.send();
      

      如果有多個字段同名,它們的值會被連接為一個字符串,每個字段之間使用“逗號+空格”分隔。

      XMLHttpRequest.getAllResponseHeaders()

      XMLHttpRequest.getAllResponseHeaders()方法返回一個字符串,表示服務(wù)器發(fā)來的所有 HTTP 頭信息。格式為字符串,每個頭信息之間使用CRLF分隔(回車+換行),如果沒有收到服務(wù)器回應(yīng),該屬性為null。如果發(fā)生網(wǎng)絡(luò)錯誤,該屬性為空字符串。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "foo.txt", true);
      xhr.send();
      
      xhr.onreadystatechange = function () {
        if (this.readyState === 4) {
          var headers = xhr.getAllResponseHeaders();
        }
      }
      

      上面代碼用于獲取服務(wù)器返回的所有頭信息。它可能是下面這樣的字符串。

      date: Fri, 08 Dec 2017 21:04:30 GMT\r\n
      content-encoding: gzip\r\n
      x-content-type-options: nosniff\r\n
      server: meinheld/0.6.1\r\n
      x-frame-options: DENY\r\n
      content-type: text/html; charset=utf-8\r\n
      connection: keep-alive\r\n
      strict-transport-security: max-age=63072000\r\n
      vary: Cookie, Accept-Encoding\r\n
      content-length: 6502\r\n
      x-xss-protection: 1; mode=block\r\n
      

      然后,對這個字符串進行處理。

      var arr = headers.trim().split(/[\r\n]+/);
      var headerMap = {};
      
      arr.forEach(function (line) {
        var parts = line.split(": ");
        var header = parts.shift();
        var value = parts.join(": ");
        headerMap[header] = value;
      });
      
      headerMap["content-length"] // "6502"
      

      XMLHttpRequest.abort()

      XMLHttpRequest.abort()方法用來終止已經(jīng)發(fā)出的 HTTP 請求。調(diào)用這個方法以后,readyState屬性變?yōu)?,status屬性變?yōu)?。

      var xhr = new XMLHttpRequest();
      xhr.open("GET", "http://www.example.com/page.php", true);
      setTimeout(function () {
      ??if (xhr) {
      ????xhr.abort();
      ????xhr = null;
      ??}
      }, 5000);
      

      上面代碼在發(fā)出5秒之后,終止一個 AJAX 請求。

      XMLHttpRequest 實例的事件

      readyStateChange 事件

      readyState屬性的值發(fā)生改變,就會觸發(fā) readyStateChange 事件。

      我們可以通過onReadyStateChange屬性,指定這個事件的監(jiān)聽函數(shù),對不同狀態(tài)進行不同處理。尤其是當狀態(tài)變?yōu)?的時候,表示通信成功,這時回調(diào)函數(shù)就可以處理服務(wù)器傳送回來的數(shù)據(jù)。

      progress 事件

      上傳文件時,XMLHttpRequest 實例對象本身和實例的upload屬性,都有一個progress事件,會不斷返回上傳的進度。

      var xhr = new XMLHttpRequest();
      
      function updateProgress (oEvent) {
        if (oEvent.lengthComputable) {
          var percentComplete = oEvent.loaded / oEvent.total;
        } else {
          console.log("無法計算進展");
        }
      }
      
      xhr.addEventListener("progress", updateProgress);
      
      xhr.open();
      

      load 事件、error 事件、abort 事件

      load 事件表示服務(wù)器傳來的數(shù)據(jù)接收完畢,error 事件表示請求出錯,abort 事件表示請求被中斷(比如用戶取消請求)。

      var xhr = new XMLHttpRequest();
      
      xhr.addEventListener("load", transferComplete);
      xhr.addEventListener("error", transferFailed);
      xhr.addEventListener("abort", transferCanceled);
      
      xhr.open();
      
      function transferComplete() {
        console.log("數(shù)據(jù)接收完畢");
      }
      
      function transferFailed() {
        console.log("數(shù)據(jù)接收出錯");
      }
      
      function transferCanceled() {
        console.log("用戶取消接收");
      }
      

      loadend 事件

      abort、load和error這三個事件,會伴隨一個loadend事件,表示請求結(jié)束,但不知道其是否成功。

      xhr.addEventListener("loadend", loadEnd);
      
      function loadEnd(e) {
        console.log("請求結(jié)束,狀態(tài)未知");
      }
      

      timeout 事件

      服務(wù)器超過指定時間還沒有返回結(jié)果,就會觸發(fā) timeout 事件,具體的例子參見timeout屬性一節(jié)。

      Navigator.sendBeacon()

      用戶卸載網(wǎng)頁的時候,有時需要向服務(wù)器發(fā)一些數(shù)據(jù)。很自然的做法是在unload事件或beforeunload事件的監(jiān)聽函數(shù)里面,使用XMLHttpRequest對象發(fā)送數(shù)據(jù)。但是,這樣做不是很可靠,因為XMLHttpRequest對象是異步發(fā)送,很可能在它即將發(fā)送的時候,頁面已經(jīng)卸載了,從而導(dǎo)致發(fā)送取消或者發(fā)送失敗。

      解決方法就是unload事件里面,加一些很耗時的同步操作。這樣就能留出足夠的時間,保證異步 AJAX 能夠發(fā)送成功。

      function log() {
        let xhr = new XMLHttpRequest();
        xhr.open("post", "/log", true);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.send("foo=bar");
      }
      
      window.addEventListener("unload", function(event) {
        log();
      
        // a time-consuming operation
        for (let i = 1; i < 10000; i++) {
          for (let m = 1; m < 10000; m++) { continue; }
        }
      });
      

      上面代碼中,強制執(zhí)行了一次雙重循環(huán),拖長了unload事件的執(zhí)行時間,導(dǎo)致異步 AJAX 能夠發(fā)送成功。

      類似的還可以使用setTimeout。下面是追蹤用戶點擊的例子。

      // HTML 代碼如下
      // <a id="target" >click</a>
      const clickTime = 350;
      const theLink = document.getElementById("target");
      
      function log() {
        let xhr = new XMLHttpRequest();
        xhr.open("post", "/log", true);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.send("foo=bar");
      }
      
      theLink.addEventListener("click", function (event) {
        event.preventDefault();
        log();
      
        setTimeout(function () {
          window.location.href = theLink.getAttribute("href");
        }, clickTime);
      });
      

      上面代碼使用setTimeout,拖延了350毫秒,才讓頁面跳轉(zhuǎn),因此使得異步 AJAX 有時間發(fā)出。

      這些做法的共同問題是,卸載的時間被硬生生拖長了,后面頁面的加載被推遲了,用戶體驗不好。

      為了解決這個問題,瀏覽器引入了Navigator.sendBeacon()方法。這個方法還是異步發(fā)出請求,但是請求與當前頁面線程脫鉤,作為瀏覽器進程的任務(wù),因此可以保證會把數(shù)據(jù)發(fā)出去,不拖延卸載流程。

      window.addEventListener("unload", logData, false);
      
      function logData() {
        navigator.sendBeacon("/log", analyticsData);
      }
      

      Navigator.sendBeacon方法接受兩個參數(shù),第一個參數(shù)是目標服務(wù)器的 URL,第二個參數(shù)是所要發(fā)送的數(shù)據(jù)(可選),可以是任意類型(字符串、表單對象、二進制對象等等)。

      navigator.sendBeacon(url, data)
      

      這個方法的返回值是一個布爾值,成功發(fā)送數(shù)據(jù)為true,否則為false。

      該方法發(fā)送數(shù)據(jù)的 HTTP 方法是 POST,可以跨域,類似于表單提交數(shù)據(jù)。它不能指定回調(diào)函數(shù)。

      下面是一個例子。

      // HTML 代碼如下
      // <body onload="analytics("start")" onunload="analytics("end")">
      
      function analytics(state) {
        if (!navigator.sendBeacon) return;
      
        var URL = "http://example.com/analytics";
        var data = "state=" + state + "&location=" + window.location;
        navigator.sendBeacon(URL, data);
      }
      

      總結(jié)

      到此這篇關(guān)于面試必備之a(chǎn)jax原始請求的文章就介紹到這了,更多相關(guān)ajax原始請求內(nèi)容請搜索以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持!

      標簽: Ajax
      相關(guān)文章:
      主站蜘蛛池模板: 国内精品亚洲 | 正在播放国产一区 | 中文字幕一精品亚洲无线一区 | 亚洲 欧美 中文 日韩欧美 | 欧美日韩一级片在线观看 | 婷婷综合在线观看丁香 | 国产三区二区 | 高清视频一区 | 欧美日韩亚洲一区二区精品 | 一区二区三区欧美在线 | 国产成人啪午夜精品网站男同 | 国产不卡视频一区二区在线观看 | 九色婷婷 | 亚洲欧美日韩精品永久在线 | 欧美日韩另类在线观看视频 | 1024你懂的国产 | bbixx在线| 欧美日本一区亚洲欧美一区 | 欧美特黄a级高清免费大片 欧美特黄a级高清免费看片 | 久久久青草青青亚洲国产免观 | 精品国产91在线网 | 一级特黄录像免费播放中文 | 国产免费爽爽视频免费可以看 | 午夜两性mp4| 国产精品福利一区二区 | 久久福利资源网站免费看 | 日韩岛国大片 | 国产精品麻豆网站 | 另类bdsm欧美变态 | 成人欧美在线 | 青青青国产精品国产精品久久久久 | 91精品国产亚一区二区三区 | 最新亚洲人成网站在线影院 | 久久婷婷色 | 久久九色综合九色99伊人 | 久久精品国产半推半就 | 在线视频一二三区2021不卡 | 成人免费淫片在线费观看 | 一区二区高清在线 | 久久网国产 | 黄色视屏免费在线观看 |