1. 程式人生 > >XMLHttpRequest物件詳解

XMLHttpRequest物件詳解

XMLHttpRequest提供了一組用於客戶端和伺服器之間傳輸資料的API

從XMLHttpRequest介面來看:

[NoInterfaceObject]
interface XMLHttpRequestEventTarget: EventTarget {
    attribute EventHandler onloadstart;
    attribute EventHandler onprogress;
    attribute EventHandler onabort;
    attribute EventHandler onerror;
    attribute EventHandler onload;
    attribute EventHandler ontimeout;
    attribute EventHandler onloaded;
};

interface
XMLHttpRequestUpload: XMLHttpRequestEventTarget { }; enum XMLHttpRequestResponseType { "", "arraybuffer", "blob", "document", "json", "text" }; [Constructor] interface XMLHttpRequest: XMLHttpRequestEventTarget { //event handler attribute EventHandler onreadystatechange; //states
const unsigned short UNSENT = 0; const unsigned short OPENED = 1; const unsigned short HEADERS_RECEIVED = 2; const unsigned short LOADING = 3; const unsigned short DONE = 4; readonly attribute unsigned short readyState; //request void open(ByteString method,[EnsureUTF16] DOMString url); void
open(ByteString method,[EnsureUTF16] DOMString url,boolean async,optional [EnsureUTF16] DOMString? username = null,optional [EnsureUTF16] DOMString? password = null); void setRequestHeader(ByteString header,ByteString value); attribute unsigned lond timeout; attribute boolean withCredentials; readonly attribute XMLHttpRequestUpload upload; void send(optional (ArrayBufferView or Blob or [EnsureUTF16] DOMString or FormData)?data=null); //response ByteString?getResponseHeader(ByteString header); ByteString?getAllResponseHeader(); void overrideMimeType(DOMString mime); readonly attribute unsigned short status; readonly attribute ByteString statusText; attribute XMLHttpRequestResponseType responseType; readonly attribute any response; readonly attribute DOMString responseText; readonly attribute Document? responseXML; }

每一個XMLHttpRequest都有一個唯一的與之關聯的XMLHttpRequestUpload物件
例項:

    var formData = new FormData();
    formData.append('name','Kuang');
    formData.append('password','Kuang')

    var xhr = new XMLHttpRequest();
    xhr.timeout = 300;
    xhr.responseType = 'json';
    xhr.open('POST',test.json',true);
    xhr.onreadystatechange = function() {
        if(this.readyState === this.DONE){
            if(this.status === 200 || this.status === 304){

            }
        }
    }
    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    xhr.send(formData);

XMLHttpRequest詳解

事件

實現XMLHttpRequestEventTarget的事件:

    onloadstart
    onprogress
    onabort
    onerror
    onload
    ontimeout
    onloaded

自身定義的事件:

    onreadystatechange

狀態

常量:

    UNSENT = 0
    OPENED = 1;
    HEADERS_RECEIVED = 2;
    LOADING = 3;
    DONE = 4;

readyState是一個只讀屬性可取以上五個常量的值,當readyState改變是將出發onreadystatechange事件。

request相關

方法
open()開啟一個請求

    open(method,url,async,[name],[password]);
    method: 請求方法POST,GET
    url: 請求地址
    async: 是否使用非同步方式發起請求

setRequestHeader()設定請求頭

    setRequestHeader(header,value);
    header: 請求頭型別
    value: 請求頭值
    採用追加方式設定

send()發起請求

    send(arraybuffer|blob|formdata|string);
    發起一個請求,可附帶資料,傳送query string時需要設定setRequestheader('Content-Type','application/x-www-form-urlencoded')

屬性

    timeout             
    //設定請求超時時間
    withCredentials
    /*
    發起同域請求時,request header中會自動新增上cookie。而傳送跨域請求時cookie並不會新增進request header

    造成這個問題的原因是:在CORS標準中做了規定,預設情況下,瀏覽器在傳送跨域請求時,不能傳送任何認證資訊(credentials)如"cookies""HTTP authentication schemes"。除非xhr.withCredentials為true(xhr物件有一個屬性叫withCredentials,預設值為false)。

    所以根本原因是cookies也是一種認證資訊,在跨域請求中,client端必須手動設定xhr.withCredentials=true,且server端也必須允許request能攜帶認證資訊(即response header中包含Access-Control-Allow-Credentials:true),這樣瀏覽器才會自動將cookie加在request header中。

    另外,要特別注意一點,一旦跨域request能夠攜帶認證資訊,server端一定不能將Access-Control-Allow-Origin設定為*,而必須設定為請求頁面的域名。
    */
    upload
    //XMLHttpRequestUpload
    物件使用者上傳,實現了XMLHttpRequestEventTarget介面,故帶有相應的事件處理

response相關

方法:
getResponseHeader獲取某一請求頭

    getResponseHeader(header);
    //返回特定請求頭的值

getAllResponseHeader獲取全部請求頭

    getAllResponseHeader()
    //返回所有請求頭組成的字串

overrideMimeType

overrideMimeType是xhr level 1就有的方法,所以瀏覽器相容性良好。這個方法的作用就是用來重寫response的content-type,這樣做有什麼意義呢?比如:server 端給客戶端返回了一份document或者是 xml文件,我們希望最終通過xhr.response拿到的就是一個DOM物件,那麼就可以用xhr.overrideMimeType(‘text/xml; charset = utf-8’)來實現。
獲取圖片的例項

    var xhr = new XMLHttpRequest();
    //向 server 端獲取一張圖片
    xhr.open('GET', '/path/to/image.png', true);

    // 這行是關鍵!
    //將響應資料按照純文字格式來解析,字符集替換為使用者自己定義的字符集
    xhr.overrideMimeType('text/plain; charset=x-user-defined');

    xhr.onreadystatechange = function(e) {
      if (this.readyState == 4 && this.status == 200) {
        //通過 responseText 來獲取圖片檔案對應的二進位制字串
        var binStr = this.responseText;
        //然後自己再想方法將逐個位元組還原為二進位制資料
        for (var i = 0, len = binStr.length; i < len; ++i) {
          var c = binStr.charCodeAt(i);
          //String.fromCharCode(c & 0xff);
          var byte = c & 0xff; 
        }
      }
    };

    xhr.send();

程式碼示例中xhr請求的是一張圖片,通過將 response 的 content-type 改為’text/plain; charset=x-user-defined’,使得 xhr 以純文字格式來解析接收到的blob 資料,終端使用者通過this.responseText拿到的就是圖片檔案對應的二進位制字串,最後再將其轉換為 blob 資料。

屬性:
status
請求成功後的狀態

statusText
請求成功後的狀態文字

responseType
responseType是xhr level 2新增的屬性,用來指定xhr.response的資料型別,目前還存在些相容性問題,可以參考本文的【XMLHttpRequest的相容性】這一小節。那麼responseType可以設定為哪些格式呢,我簡單做了一個表,如下:

資料型別 說明
“” String字串 預設不設定responseType時
text Sting字串
arraybuffer ArrayBuffer物件
blob Blob對像
formdata FormData物件 FormData例項
document Document物件 希望返回XML格式資料時使用

下面是同樣是獲取一張圖片的程式碼示例,相比xhr.overrideMimeType,用xhr.response來實現簡單得多。

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/path/to/image.png', true);
    //可以將`xhr.responseType`設定為`"blob"`也可以設定為`" arrayBuffer"`
    //xhr.responseType = 'arrayBuffer';
    xhr.responseType = 'blob';

    xhr.onload = function(e) {
      if (this.status == 200) {
        var blob = this.response;
        ...
      }
    };

    xhr.send();

response
返回與設定的responseType一致的資料
responseText
當responseType為"text"""時才有此屬性
responseXML
當responseType為"text"""doument時才有此屬性