BOM 瀏覽器對象模型_XMLHttpRequest 對象

XMLHttpRequest 對象php

瀏覽器與服務器之間,採用 HTTP 協議 通訊。html

用戶在瀏覽器地址欄鍵入一個網址,或者經過網頁表單向服務器提交內容,這時瀏覽器就會向服務器發出 HTTP 請求json

AJAX跨域

2005.02 提出的概念 ---- Asynchronous JavaScript and XML數組

經過 JavaScript 的異步通訊,從服務器獲取 XML 文檔從中提取數據,再更新當前網頁的對應部分,而不用刷新整個網頁瀏覽器

  • 一般概念:

JavaScript 腳本發起 HTTP 通訊的代名詞服務器

也就是說,只要用腳本發起通訊,就能夠叫作 AJAX 通訊
網絡

  • W3C 也在2006年發佈了它的國際標準

1. 建立 XMLHttpRequest 實例app

var xhr = new XMLHttpRequest();異步

 

2. 發出 HTTP 請求

// 向指定的服務器網址,發出 GET 請求

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

3. 接收服務器傳回的數據

// 監聽通訊狀態(readyState屬性)的變化

xhr.onreadystatechange = handleStateChange;

function handleStateChange(){... ...}

4. 更新網頁數據

// 一旦拿到服務器返回的數據,AJAX 不會刷新整個網頁,而是隻更新網頁裏面的相關部分,從而不打斷用戶正在作的事情

歸納爲: AJAX 經過原生的 XMLHttpRequest 對象發出 HTTP 請求,獲得服務器返回的數據後,再進行處理

注意: 

如今,服務器返回的都是 JSON 格式的數據,XML 格式已通過時了

AJAX 這個名字已經成了一個通用名詞,字面含義已經消失了

XMLHttpRequest 對象是 AJAX 的主要接口,用於瀏覽器與服務器之間的通訊

不止 XML 和 Http,實際可使用多種協議(如fileftp)發送任何格式的數據(字符串、二進制)

AJAX 只能向同源網址(協議域名端口都相同)發出 HTTP 請求,若是發出跨域請求,就會報錯

使用實例的 abort() 方法,終止 XMLHttpRequest 請求,也會形成 readyState 屬性變化,致使調用  XMLHttpRequest.onreadystatechange 屬性

XMLHttpRequest 的實例屬性

  • XMLHttpRequest.readyState ---- 整數,表示實例對象的當前狀態

該屬性只讀。它可能返回如下值。

0    表示 XMLHttpRequest 實例已經生成,可是實例的 open() 方法尚未被調用。
1    表示 open() 方法已經調用,可是實例的 send() 方法尚未調用

仍然可使用實例的 setRequestHeader() 方法,設定 HTTP 請求的頭信息。

2    表示實例的 send() 方法已經調用,而且服務器返回的頭信息和狀態碼已經收到。
3    表示正在接收服務器傳來的數據體(body 部分)

這時,若是實例的 responseType 屬性等於 text 或者空字符串

responseText 屬性就會包含已經收到的部分信息。

4    表示服務器返回的數據已經徹底接收,或者本次接收已經失敗

  • var xhr = new XMLHttpRequest();
    
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        handler(xhr.response);
     } }
  • XMLHttpRequest.response ---- 服務器返回的數據體(即 HTTP 迴應的 body 部分)

該屬性只讀

它多是任何數據類型,好比字符串、對象、二進制對象等等

  • 具體的類型由 XMLHttpRequest.responseType ---- 字符串 屬性決定。

表示服務器返回數據的類型。

這個屬性是可寫的,能夠在調用 open() 方法以後、調用 send() 方法以前,設置這個屬性的值,告訴服務器返回指定類型的數據

若是 responseType 設爲空字符串,就等同於默認值 text

 

  • "text"        字符串
  • ""(空字符串)        等同於text,表示服務器返回文本數據

適合大多數狀況,並且直接處理文本也比較方便

 

  • "arraybuffer"        ArrayBuffer 對象,表示服務器返回二進制數組
  • 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();
  • "blob"        Blob 對象,表示服務器返回二進制對象

適合讀取二進制數據,好比圖片文件

  • 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();
  • "document"        Document 對象,表示服務器返回一個文檔對象

適合返回 HTML / XML 文檔的狀況

這意味着,對於那些打開 CORS 的網站,能夠直接用 Ajax 抓取網頁

而後不用解析 HTML 字符串,直接對抓取回來的數據進行 DOM 操做

  • "json"        JSON 對象

若是將這個屬性設爲json,瀏覽器就會自動對返回數據調用 JSON.parse() 方法

也就是說,從 xhr.response 屬性(注意,不是xhr.responseText屬性)獲得的不是文本,而是一個 JSON 對象

 

若是本次請求沒有成功或者數據不完整,該屬性等於null

可是,若是 responseType 屬性等於 text 或空字符串

在請求沒有結束以前(readyState 等於 3 的階段)

XMLHttpRequest.response 屬性包含服務器已經返回的部分數據

  • XMLHttpRequest.responseText --- 從服務器接收到的字符串

該屬性爲只讀

只有 HTTP 請求完成接收之後,該屬性纔會包含完整的數據

  • 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 ---- 直接解析後的文檔 DOM 樹

生效的前提是 HTTP 迴應的 Content-Type 頭信息等於 text/xmlapplication/xml

在發送請求前,XMLHttpRequest.responseType 屬性要設爲 document

若是 HTTP 迴應的 Content-Type 頭信息不等於 text/xml 和 application/xml ,

可是又想從 responseXML 拿到數據(即把數據按照 DOM 格式解析),

那麼須要手動調用 XMLHttpRequest.overrideMimeType() 方法,強制進行 XML 解析

  • var xhr = new XMLHttpRequest();
    xhr.open('GET', '/server', true);
    
    xhr.responseType = 'document';
    xhr.overrideMimeType('text/xml');    // 強制進行 XML 解析
    
    xhr.onload = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.responseXML);    // 獲得的數據,是直接解析後的文檔 DOM 樹
      }
    };
    
    xhr.send(null);

返回從服務器接收到的 HTML 或 XML 文檔對象,該屬性爲只讀。

若是本次請求沒有成功,或者收到的數據不能被解析爲 XML 或 HTML,該屬性等於 null

XMLHttpRequest.responseURL ---- 字符串,表示發送數據的服務器的網址

  • 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()方 法指定的請求網址不必定相同

若是服務器端發生跳轉,這個屬性返回最後實際返回數據的網址

另外,若是原始 URL 包括錨點(fragment),該屬性會把錨點剝離

XMLHttpRequest.status ---- 整數,表示服務器迴應的 HTTP 狀態碼

通常來講,若是通訊成功的話,這個狀態碼是200;

若是服務器沒有返回狀態碼,那麼這個屬性默認是 200。

請求發出以前,該屬性爲 0。該屬性只讀

 

  • 200        OK,訪問正常
  • 301        Moved Permanently,永久移動
  • 302        Moved temporarily,暫時移動
  • 304        Not Modified,未修改
  • 307        Temporary Redirect,暫時重定向
  • 401        Unauthorized,未受權
  • 403        Forbidden,禁止訪問
  • 404        Not Found,未發現指定網址
  • 500        Internal Server Error,服務器發生錯誤

XMLHttpRequest.statusText ---- 返回一個字符串,表示服務器發送的狀態提示

該屬性只讀,包含整個狀態信息,好比 「OK」 和 「Not Found」

在請求發送以前(即調用 open() 方法以前),該屬性的值是空字符串

若是服務器沒有返回狀態提示,該屬性的值默認爲"「OK」

XMLHttpRequest.timeout ---- 整數,表示多少毫秒後,若是請求仍然沒有獲得結果,就會自動終止

若是該屬性等於 0 ,就表示沒有時間限制

XMLHttpRequestEventTarget.ontimeout ---- 用於設置一個監聽函數,若是發生 timeout 事件,就會執行這個監聽函數

  • 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) {
                // 處理服務器返回的數據
            } else {
                console.error(xhr.statusText);
            }
        }
    };
    
    xhr.open('GET', url, true);
    
    // 指定 10 秒鐘超時
    xhr.timeout = 10 * 1000;
    xhr.send(null);

XMLHttpRequest.withCredentials ---- 布爾值,表示跨域請求時,用戶信息(好比 Cookie 和認證的 HTTP 頭信息)是否會包含在請求之中

默認爲 false,即向 example.com 發出跨域請求時,不會發送example.com設置在本機上的 Cookie(若是有的話)

withCredentials屬性打開的話,跨域請求不只會發送 Cookie,還會設置遠程主機指定的 Cookie

若是須要跨域 AJAX 請求發送 Cookie,須要 withCredentials 屬性設爲true。注意,同源的請求不須要設置這個屬性

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

    爲了讓這個屬性生效,服務器必須顯式返回Access-Control-Allow-Credentials這個頭信息

  • Access-Control-Allow-Credentials: true

XMLHttpRequest 事件監聽函數

 

.onloadstart        loadstart 事件        (HTTP 請求發出)的監聽函數
.onprogress        progress 事件        (正在發送和加載數據)的監聽函數
.onabort        abort 事件        (請求停止,好比用戶調用了abort()方法)的監聽函數
.onerror        error 事件        (請求失敗)的監聽函數

注意,若是發生網絡錯誤(好比服務器沒法連通),onerror 事件沒法獲取報錯信息

也就是說,可能沒有錯誤對象,因此這樣只能顯示報錯的提示

.onload        load 事件        (請求成功完成)的監聽函數
.ontimeout        timeout 事件        (用戶指定的時限超過了,請求還未完成)的監聽函數
.onloadend        loadend 事件        (請求完成,無論成功或失敗)的監聽函數

全部這些監聽函數裏面,只有 progress 事件的監聽函數有事件對象參數,該對象有三個屬性

loaded        返回 已經傳輸的數據量

total        屬性返回 總的數據量

lengthComputable        返回一個布爾值,表示加載的進度是否能夠計算

AJAX 文件上傳

發送文件之後,經過 XMLHttpRequest.upload 屬性能夠獲得一個對象,經過觀察這個對象,能夠得知上傳的進展

主要方法就是監聽這個對象的各類事件:loadstart、loadend、load、abort、error、progress、timeout

假定網頁上有一個 <progress> 元素

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

    指定progress事件的監聽函數,便可得到上傳的進度

  • 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()

用於指定 HTTP 請求的參數,或者說初始化 XMLHttpRequest 實例對象。

它一共能夠接受五個參數

  • void open( string method, // method:表示 HTTP 動詞方法,好比 GET、POST、PUT、DELETE、HEAD等。 string url, // 表示請求發送目標 URL optional boolean async, // 布爾值,表示請求是否爲異步,默認爲 true。該參數可選。 // 若是設爲 false,則 send() 方法只有等到收到服務器返回告終果,纔會進行下一步操做。 // 因爲同步 AJAX 請求會形成瀏覽器失去響應,許多瀏覽器已經禁止在主線程使用,只容許 Worker 裏面使用。 // 因此,這個參數輕易不該該設爲 false optional string user, // 表示用於認證的用戶名,默認爲空字符串。該參數可選 optional string password // 表示用於認證的密碼,默認爲空字符串。該參數可選 );

若是對使用過 open() 方法的 AJAX 請求,再次使用這個方法,等同於調用 abort(),即終止請求

XMLHttpRequest.send()

用於實際發出 HTTP 請求

它的參數是可選的,

若是不帶參數,就表示 HTTP 請求只有一個 URL,沒有數據體,典型例子就是 GET 請求

  • var xhr = new XMLHttpRequest();
    xhr.open('GET',
        'http://www.example.com/?id=' + encodeURIComponent(id),    // GET請求的參數,做爲查詢字符串附加在 URL 後面
        true
    );
    xhr.send(null);

若是帶有參數,就表示除了頭信息,還帶有包含具體數據的信息體,典型例子就是 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 全部的監聽事件,都必須在 send() 方法調用以前設定

 

參數就是發送的數據。多種格式的數據,均可以做爲它的參數

void send();
void send(ArrayBufferView data);
void send(Blob data);    // 若是發送二進制數據,最好是發送ArrayBufferView或Blob對象,這使得經過 Ajax 上傳文件成爲可能
void send(Document data);    // 若是send()發送 DOM 對象,在發送以前,數據會先被串行化
void send(String data);
void send(FormData data);

  • 發送表單數據的例子
  • 1
  • var formData = new FormData();
    
    formData.append('username', '張三');
    formData.append('email', 'zhangsan@example.com');
    formData.append('birthDate', 1940);
    
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/register');
    xhr.send(formData);
  • 與發送下面的 表單數據 是同樣的
  • <form id='registration' name='registration' action='/register'>
      <input type='text' name='username' value='張三'>
      <input type='email' name='email' value='zhangsan@example.com'>
      <input type='number' name='birthDate' value='1940'>
      <input type='submit' onclick='return sendForm(this.form);'>
    </form>
  • 使用 FormData 對象加工表單數據,而後再發送
  • 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()

用於設置瀏覽器發送的 HTTP 請求的頭信息。

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

     

  • 首先設置頭信息 Content-Type,表示發送 JSON 格式的數據

  • 而後設置 Content-Length,表示數據長度

  • 最後發送 JSON 數據。

該方法必須在open()以後、send()以前調用。

該方法接受兩個參數

第一個參數是字符串,表示頭信息的字段名

第二個參數是字段值

若是該方法屢次調用,設定同一個字段,則每一次調用的值會被合併成一個單一的值發送。

XMLHttpRequest.overrideMimeType()

用來指定 MIME 類型,覆蓋服務器返回的真正的 MIME 類型,從而讓瀏覽器進行不同的處理。

舉例來講,服務器返回的數據類型是 text/xml,因爲種種緣由瀏覽器解析不成功報錯,這時就拿不到數據了。

爲了拿到原始數據,咱們能夠把 MIME 類型改爲 text/plain,這樣瀏覽器就不會去自動解析,從而咱們就能夠拿到原始文本了

  • xhr.overrideMimeType('text/plain')

修改服務器返回的數據類型,不是正常狀況下應該採起的方法。

若是但願服務器返回指定的數據類型,能夠用 responseType 屬性告訴服務器,就像下面的例子。

只有在服務器沒法返回某種數據類型時,才使用 overrideMimeType() 方法

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

XMLHttpRequest.getResponseHeader()

返回 HTTP 頭信息指定字段的值

若是尚未收到服務器迴應或者指定字段不存在,返回 null。

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

該方法的參數不區分大小寫

若是有多個字段同名,它們的值會被鏈接爲一個字符串,每一個字段之間使用 「逗號+空格」 分隔

XMLHttpRequest.getAllResponseHeaders()

返回一個字符串,表示服務器發來的全部 HTTP 頭信息。

格式爲字符串,每一個頭信息之間使用 CRLF 分隔(回車+換行)

若是沒有收到服務器迴應,該屬性爲null

若是發生網絡錯誤,該屬性爲空字符串

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

    上面代碼用於獲取服務器返回的全部頭信息。它多是下面這樣的字符串

  • 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

而後,對這個字符串 header 進行處理

  • 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()

用來終止已經發出的 HTTP 請求。

調用這個方法之後,readyState 屬性變爲 4,status 屬性變爲0

舉個例子: 發出5秒以後,終止一個 AJAX 請求

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

重要的事件

readyStateChange 事件

readyState 屬性的值發生改變,就會觸發 readyStateChange 事件

咱們能夠經過onReadyStateChange屬性,指定這個事件的監聽函數,對不一樣狀態進行不一樣處理

尤爲是當狀態變爲 4 的時候,表示通訊成功,這時回調函數就能夠處理服務器傳送回來的數據

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 事件       表示請求被中斷(好比用戶取消請求)

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

Navigator.sendBeacon() 用戶卸載網頁的時候,有時須要向服務器發一些數據

XMLhttpRequest對象是異步發送,極可能在它即將發送的時候,頁面已經卸載了

這個方法仍是異步發出請求,可是請求與當前頁面脫鉤,做爲瀏覽器的任務,所以能夠保證會把數據發出去,不拖延卸載流程

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

第一個參數是目標服務器的 URL

第二個參數是所要發送的數據(可選),能夠是任意類型(字符串、表單對象、二進制對象等等)

成功發送數據 返回 true,不然返回爲 false

發送數據的 HTTP 方法是 POST,能夠跨域,相似於表單提交數據。它不能指定回調函數

  • // 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); }
相關文章
相關標籤/搜索