## AJAX
超文本傳輸協議(HyperText Transfer Protocol,HTTP)是用于從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議(transport)。它可以使瀏覽器更加高效,使網絡傳輸減少。
Ajax(Asynchronous JavaScript and XML)描述了一種主要使用腳本操縱HTTP的Web應用架構。
Ajax的主要特點是使用腳本操縱HTTP和Web服務器進行數據交換,不會導致頁面重載。
AJAX技術的核心是XMLHttpRequest對象(簡稱XHR)。
**一、XMLHttpRequest對象**
所有瀏覽器(IE7之前除外)都支持XMLHttpRequest對象,它定義了用腳本操縱HTTP的API。除了常用的GET請求,這個API還包含實現POST請求的能力,同時它能用文本或Document對象的形式返回服務器的響應。
瀏覽器在XMLHttpRequest類上定義了它們的HTTP API,這個類的每個實例都表示一個獨立的請求/響應對,并且這個對象的屬性和方法允許指定請求細節和提取響應數據。
具體來說,AJAX包括以下幾個步驟:
- 創建AJAX對象(實例化XMLHttpRequest對象)
- 發起HTTP請求
- 接收服務器傳回的數據
- 更新網頁數據
**1.1實例化**
實例化XMLHttpRequest對象:
```
var xhr = new XMLHttpRequest();
```
注意:你可以重用已存在的XMLHttpRequest,但這將會終止之前通過該對象掛起的任何請求。
由于IE7之前的版本不支持非標準的XMLHttpRequest()構造函數,不過能如下模擬:
```
function createXHR(){
if ( typeof XMLHttpRequest != 'undefined'){
return new XMLHttpRequest();
}else if(typeof ActiveXObject != 'undefined'){
if(typeof arguments.callee.activeXString != 'string'){
var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'], i, len;
for(i = 0, len = versions.length; i < len; i++){
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
}catch(e){
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error('No XHR object available');
}
}
```
一個HTTP請求由4部分組成:
- HTTP請求方法或動作(verb)
- 正在請求的URL
- 一個可選的請求頭集合,其中可能包括身份驗證信息
- 一個可選的請求主體
服務器返回的HTTP響應包含3部分:
- 一個數字和文字組成的狀態碼,用來顯示請求的成功和失敗
- 一個響應頭集合
- 響應主體
注意:使用XMLHttpRequest時,必須把文件放到Web服務器上。因為AJAX只能向同源網址(協議、域名、端口都相同)發出HTTP請求,如果發出跨源請求,就會報錯
**1.2 指定請求**
**1.2.1 open()**
創建XMLHttpRequest對象后,就可以調用XMLHttpRequest對象的open()方法去指定這個請求的兩個必需部分:方法和URL。
```
xhr.open('GET','example.php');
```
上面代碼向指定的服務器網址,啟動GET請求。
open()的第一個參數指定HTTP方法或動作(常用的是“GET”和“POST”),這個字符串不區分大小寫,但通常使用大寫字母來匹配HTTP協議。“DELETE”、“HEAD”、“OPTONS”、“PUT”也可以作為open()方法的第1個參數。
第二個參數是URL(跨域的請求通常會報錯),它是請求的主題。
還有第三個可選參數,表示是否異步發送請求的布爾值(true同步,false異步,默認false)
調用open()方法并不會真正發送請求,而只是啟動一個請求以備發送。
**1.2.2 HTTP頭部信息**
每個HTTP請求和響應都會帶有相應的頭部信息。
XHR對象也提供了操作這兩種頭部(即請求頭部和響應頭部)信息的方法。
默認情況下,在發送XHR請求的同時,還會發送下列頭部信息:
```
Accept: 瀏覽器能夠處理的內容類型
Accept-Charset: 瀏覽器能夠顯示的字符集
Accept-Encoding:瀏覽器能夠處理的壓縮編碼。
Accept-Language: 瀏覽器當前設置的語言。
Connection:瀏覽器與服務器之間連接的類型
Cookie:當前頁面設置的任何Cookie
Host:發出請求的頁面所在的域。
Referer:發出請求的頁面的URI。
User-Agent:瀏覽器的用戶代理字符串
```
如果有請求頭,我們可以設置它。例如,POST請求需要“Content-Type”頭指定請求主題的MIME類型。
```
xhr.setRequestHeader('Content-Type','text/plain');
```
注意:如果對相同的頭調用setRequestHeader()多次,新值不會取代之前指定的值,相反,HTTP請求將包含這個頭的多個副本或這個頭將指定多個值。
必須在調用open()方法只會且調用send()方法之前調用setRequestHeader()。
**1.2.3 send()**
使用XMLHttpRequest發起HTTP請求的最后一步是指定可選的請求主體的數據并向服務器發送它。
```
xhr.send(null);
```
GET請求沒有主體,所以應該傳遞null或者省略這個參數。POST請求通常擁有主體,同時它應該匹配使用setRequestHeader()指定的“Content-Type”頭。
HTTP請求的各部分有指定順序:請求方法和URL首先到達,然后是請求頭,最后是請求主體。XMLHttpRequest實現通常直到調用send()方法才開始啟動網絡。
**1.2.4 GET請求**
GET是最常見的請求類型,必要時,可以將查詢字符串參數追加到URL的末尾,以便將信息發送給服務器。
注意:對于XHR來說,傳入open()方法的URL末尾的查詢字符串必須經過正確的編碼,否則可能出現字符串格式的錯誤。
查詢字符串中每個參數的名稱和值都必須使用encodeURIComponent()進行編碼,然后才能放到URL的末尾,而且所有名值對都必須由和號(&)分隔。如下所示:
```
xhr.open('get','example.php?name1=value1&name2=value2",true);
```
下面這個函數可以輔助向現有的URL的末尾添加查詢字符串參數:
```
function addURLParam(url, name, value){
url += (url.indexOf('?') == -1) ? '?' : '&';
url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
return url;
}
```
**1.2.5 POST請求**
對于POST請求,應該把數據作為請求的主題提交,它不是以地址形式傳參,而是在send()中傳參。
注意:使用POST請求時,如果不設置Content-Type頭部信息,那么發送給服務器的數據就不會出現在`$_POST`中。
**1.3 取得響應**
一個完整的HTTP響應由`狀態嗎`、`響應頭集合`和`響應主體`組成。這些都可以通過XMLHttpRequest對象的屬性和方法使用:
- `status`和`statusText`屬性以數字和文本的形式返回HTTP狀態碼。這些屬性保存標準的HTTP值。像200和“OK”表示成功請求,404和“Not Found”表示URL不能匹配服務器上的任何資源。
- 使用`getResponseHeader()`和`getAllResponseHeaders()`能查詢/獲取響應頭。XMLHttpRequest會自動處理cookie:它會從getAllResponseHeaders()頭返回集合中過濾cookie頭,而如果給getResponseHeader()傳遞“Set-Cookie”和“Set-Cookie2”,則返回null。
- 響應主體可以從responseText屬性得到文本形式的,從responseXML屬性中得到Document形式的。
為了在響應準備就緒時得到通知,我們必須監聽XMLHttpRequest對象上的`readystatechange`事件。
每當發生狀態變化的時候,readyState屬性的值就會發生改變。這個值每一次變化,都會觸發readyStateChange事件。
```
xhr.onreadystatechange=function(){}
```
**1.3.1 同步響應**
XMLHttpRequest默認是異步的,當然,如果有需要,我們也可以設置成同步(較少用):
```
xhr.open('GET','example.php',false);
```
上面的代碼中,通過傳遞第三個參數為false實現同步。要注意的是:一旦設置為同步,那么send()方法將阻塞直到請求完成。
**1.3.2 響應解碼**
如果服務器發送諸如對象或數組這樣的結構化數據作為響應,它應該傳輸JSON編碼的字符串數據。
下面是一個解析不同類型的響應值的方法:
```
function get(url,callback){
var xhr = new XMLHttpRequest(); //創建新請求
xhr.open('GET',url);
xhr.onreadystatechange=function(){
//如果請求完成且成功
if(xhr.readyState === 4 && xhr.status === 200){
//獲得響應的類型
var type = xhr.getResponseHeader('Content-type');
if(type.indexOf('xml') !== -1 && xhr.responseXML){
callback(xhr.responseXML); //Document對象響應
}else if(type === 'application/json'){
callback(JSON.parse(xhr.responseText)); //JSON響應
}else{
callback(xhr.responseText); //字符串響應
}
}
};
xhr.send(null); //立即發送請求
}
```
**1.4 編碼請求主體**
HTTP POST請求包括一個請求主體,它包含客戶端傳遞給服務器的數據。
**1.4.1 表單編碼的請求**
默認情況下,HTML表單通過POST方法發送給服務器,而編碼后的表單數據則用做請求主體。例如:
```
user=TG&age=18;
```
表單數據編碼格式有一個正式的MIME類型:
```
application/x-www-form-urlencoded
```
當使用POST方法提交這種順序的表單數據時,必須設置“Content-Type”請求頭為這個值。
```
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
```
注意:當使用form時,這不是必需值,因為這是默認方法。
當我們發送給服務器的是一個JavaScript對象時,我們也可以采取這種類型的編碼。
下面的函數encodeFormData()就是將對象轉換為表單編碼。
```
/*
* {
* name:'TG',
* age:18
* }
*/
function encodeFormData(data){
if(!data) return '';
var pairs = [];
for(var name in data){
if(!data.hasOwnProperty(name)) continue;
if(typeof data[name] === 'function') continue;
var value = data[name].toString();
name = encodeURIComponent(name.replace('%20','+'));
value = encodeURIComponent(value.replace('%20','+'));
pairs.push(name + '=' + value);
}
return pairs.join('&');
}
```
**1.4.2 JSON編碼的請求**
使用JSON編碼主體來發起HTTP POST請求
```
xhr.setRequestHeader('Content-Type','application/json');
xhr.send(JSON.stringify(data));
```
**1.5.XMLHttpRequest實例的屬性**
**(1)readyState屬性**
`readyState`是一個整數,它指定了HTTP請求的狀態。它可能的值如下:
- 0,對應常量UNSENT,表示XMLHttpRequest實例已經生成,但是open()方法還沒有被調用。
- 1,對應常量OPENED,表示open()已調用,但send()方法還沒有被調用,仍然可以使用setRequestHeader(),設定HTTP請求的頭信息。
- 2,對應常量HEADERS_RECEIVED,表示send()方法已經執行,并且頭信息和狀態碼已經收到。
- 3,對應常量LOADING,表示正在接收服務器傳來的主體(body)部分的數據,如果responseType屬性是text或者空字符串,responseText就會包含已經收到的部分信息。
- 4,對應常量DONE,表示服務器數據已經完全接收,或者本次接收已經失敗了。
在IE8之前并沒有定義這些值,但使用硬編碼值4來表示XMLHttpRequest.DONE。
**(2)status**
status屬性為只讀屬性,表示本次請求所得到的HTTP狀態碼,它是一個整數。一般來說,如果通信成功的話,這個狀態碼是200。
```
200, OK,訪問正常
301, Moved Permanently,永久移動
302, Move temporarily,暫時移動
304, Not Modified,未修改
307, Temporary Redirect,暫時重定向
401, Unauthorized,未授權
403, Forbidden,禁止訪問
404, Not Found,未發現指定網址
500, Internal Server Error,服務器發生錯誤
```
例子:
```
if(xhr.readyState === 4){
//請求完成
if(xhr.status === 200){
//請求成功
}
}
```
**(3)statusText**
statusText屬性為只讀屬性,返回一個字符串,表示服務器發送的狀態提示。不同于status屬性,該屬性包含整個狀態信息,比如”200 OK“。
**(4)timeout**
timeout屬性等于一個整數,表示多少毫秒后,如果請求仍然沒有得到結果,就會自動終止。如果該屬性等于0,就表示沒有時間限制。
對應超時,還有個監聽函數:
```
xhr.ontimeout = function(){
//請求超時
}
```
**(5)response**
response屬性為只讀,返回接收到的數據體(即body部分)。它的類型可以是ArrayBuffer、Blob、Document、JSON對象、或者一個字符串,這由XMLHttpRequest.responseType屬性的值決定。
如果本次請求沒有成功或者數據不完整,該屬性就會等于null。
**(6)responseType**
responseType屬性用來指定服務器返回數據(xhr.response)的類型。
```
”“:字符串(默認值)
“arraybuffer”:ArrayBuffer對象
“blob”:Blob對象
“document”:Document對象
“json”:JSON對象
“text”:字符串
```
text類型適合大多數情況,而且直接處理文本也比較方便,document類型適合返回XML文檔的情況,blob類型適合讀取二進制數據,比如圖片文件。
**(7)responseText**
responseText屬性返回從服務器接收到的字符串,該屬性為只讀。如果本次請求沒有成功或者數據不完整,該屬性就會等于null。
如果服務器返回的數據格式是JSON,就可以使用responseText屬性。
```
var data = xhr.responseText;
data = JSON.parse(data);
```
**(8)responseXML**
responseXML屬性返回從服務器接收到的Document對象,該屬性為只讀。如果本次請求沒有成功,或者數據不完整,或者不能被解析為XML或HTML,該屬性等于null。
返回的數據會被直接解析為DOM對象。
**(9)事件監聽接口**
XMLHttpRequest第一版,只能對`onreadystatechange`這一個事件指定回調函數。該事件對所有情況作出響應。 XMLHttpRequest第二版允許對更多的事件指定回調函數。
```
onloadstart 請求發出
onprogress 正在發送和加載數據
onabort 請求被中止,比如用戶調用了abort()方法
onerror 請求失敗
onload 請求成功完成
ontimeout 用戶指定的時限到期,請求還未完成
onloadend 請求完成,不管成果或失敗
```
**1.6.XMLHttpRequest實例的方法**
**(1)abort()**
abort方法用來終止已經發出的HTTP請求。
**(2)getAllResponseHeaders()**
getAllResponseHeaders方法返回服務器發來的所有HTTP頭信息。格式為字符串,每個頭信息之間使用CRLF分隔,如果沒有受到服務器回應,該屬性返回null。
**(3)getResponseHeader()**
getResponseHeader方法返回HTTP頭信息指定字段的值,如果還沒有收到服務器回應或者指定字段不存在,則該屬性為null。
如果有多個字段同名,則它們的值會被連接為一個字符串,每個字段之間使用“逗號+空格”分隔。
**(4)open()**
XMLHttpRequest對象的open方法用于指定發送HTTP請求的參數,它的使用格式如下,一共可以接受五個參數。
```
void open( string method, string url, optional boolean async, optional string user, optional string password);
```
參數說明:
- method:表示HTTP動詞,比如“GET”、“POST”、“PUT”和“DELETE”。
- url: 表示請求發送的網址。
- async: 格式為布爾值,默認為true,表示請求是否為異步。如果設為false,則send()方法只有等到收到服務器返回的結果,才會有返回值。
- user:表示用于認證的用戶名,默認為空字符串。
- password:表示用于認證的密碼,默認為空字符串。
**(5)send()**
send方法用于實際發出HTTP請求。如果不帶參數,就表示HTTP請求只包含頭信息,也就是只有一個URL,典型例子就是GET請求;如果帶有參數,就表示除了頭信息,還帶有包含具體數據的信息體,典型例子就是POST請求。
**(6)setRequestHeader()**
setRequestHeader方法用于設置HTTP頭信息。該方法必須在open()之后、send()之前調用。如果該方法多次調用,設定同一個字段,則每一次調用的值會被合并成一個單一的值發送。
```
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數據。
**(6)overrideMimeType()**
該方法用來指定服務器返回數據的MIME類型。該方法必須在send()之前調用。
```
// 強制將MIME改為文本類型
xhr.overrideMimeType('text/plain; charset=x-user-defined');
```
在XMLHttpRequest版本升級后,一般采用指定的responseType的方法。
```
xhr.responseType = 'text';
```
**2、 上傳文件**
講到上傳文件,我們最常用的就是使用`<input type="file">`元素選擇文件,然后表單將在它產生POST請求主體中發送文件內容。
```
<form id="form" action="upload.php" method="POST">
<input type="file" id="files" name="photos[]"/>
<button type="submit" id="upload">上傳</button>
</form>
```
如果要允許選擇多個文件,可設置file控件的multiple屬性。
```
<input type="file" multiple/>
```
**1.5.1 files屬性**
每個`<input type="file">`元素都有一個files屬性,返回一個FileList對象,它是File對象中的類數組對象,包含了用戶選擇的文件。
```
var fileInput = document.getElementById('files');
var files = fileInput.files;
```
通常情況下,對于文件上傳元素,我們都會添加change事件處理程序,每次文件信息有變化,它都會觸發。
```
fileInput.addEventListener('change',function(){
var file = this.files[0];
if(!file) return;
var xhr = new XMLHttpRequest();
xhr.open('POST','upload.php');
xhr.send(file);
},false);
```
文件類型是二進制大對象(Blob)類型中的一個子類型。XHR2允許向send()方法傳入任何Blob對象。如果沒有顯式設置Content-Type頭,這個Blob對象的type屬性用于設置待上傳的Content-Type頭。
也可以顯式設置:
```
xhr.setRequestHeader('Content-Type', file.type);
```
**1.5.2 multipart/form-data請求**
當HTML表單同時包含文件上傳元素和其他元素時,瀏覽器不能使用普通的表單編碼而必須使用成為“multipart/form-data”的特殊Content-Type頭來用POST方法提交表單。
**1.5.3 FormData對象**
XHR2定義了新的FormData API,它容易實現多部分請求主體。
首先,新建一個FormData對象的實例,用來模擬發送到服務器的表單數據,把選中的文件添加到這個對象上面。
```
var formdata = new FormData();
```
然后按需多次調用這個對象的append()方法把個體“部分”添加到請求中。
```
for(var i = 0;i < files.length; i++){
var file = files[i];
formdata.append('photos[]',file,file.name);
}
```
最后,把FormData對象傳遞給send()方法
```
xhr.send(formdata);
```
除了可以添加文件,還可以添加二進制對象(Blob)或者字符串。
```
// Files
formdata.append(name, file, filename);
// Blobs
formdata.append(name, blob, filename);
// Strings
formdata.append(name, value);
```
append方法的第一個參數是表單的控件名,第二個參數是實際的值,第三個參數是可選的,通常是文件名。
**3、HTTP進度事件**
除了使用readystatechange事件來探測HTTP請求的完成外,在XHR2中,還定義了多個有用的事件。
- abort事件:當進度事件被中止時觸發。如果發生錯誤,導致進程中止,不會觸發該事件。
- error事件:由于錯誤導致資源無法加載時觸發。
- load事件:進度成功結束時觸發。
- loadstart事件:進度開始時觸發。
- loadend事件:進度停止時觸發,發生順序排在error事件\abort事件\load事件后面。
- progress事件:當操作處于進度之中,由傳輸的數據塊不斷觸發。
- timeout事件:進度超過限時觸發。
當調用send()時,觸發單個loadstart事件。當正在加載服務器的響應時,XMLHttpRequest對象會發現progress事件,通常每隔50毫秒左右,可以使用這些事件給用戶反饋請求的進度。當事件完成,會觸發load事件。
HTTP請求無法完成有3種情況:
- 請求超時,會觸發timeout事件
- 請求終止,會觸發abort事件
- 請求發生錯誤,會觸發error事件
注意:對于任何具體請求,瀏覽器將只會觸發load、abort、timeout和error事件中的一個。一旦這些事件中的一個發生后,瀏覽器應該觸發 loadend 事件。
要使用這些事件,有兩種方式:
```
xhr.onload=function(){}
xhr.addEventListener('load',function(){})
```
**3.1 progress事件**
因為這些事件是XHR2中才定義的,所以有時需要檢查瀏覽器是否支持progress事件:
```
if('onprogress' in (new XMLHttpRequest())){
//支持progress事件
}
```
除了像type和timestamp這樣的常用Event對象屬性外,與progress事件相關聯的事件對象有3個有用的屬性:
- lengthComputable:返回一個布爾值,表示當前進度是否具有可計算的長度。如果為false,就表示當前進度無法測量。
- total:返回一個數值,表示當前進度的總長度。如果是通過HTTP下載某個資源,表示內容本身的長度,不含HTTP頭部的長度。如果lengthComputable屬性為false,則total屬性就無法取得正確的值。
- loaded:返回一個數值,表示當前進度已經完成的數量。該屬性除以total屬性,就可以得到目前進度的百分比。
我們可以利用total和loaded屬性來獲取當前進度:
```
xhr.onprogress = function(e){
if(e.lengthComputable){
var percentComplete = e.loaded / e.total;
}
}
```
**3.2 上傳進度事件**
在XHR2中,也提供了用于監控HTTP請求上傳的事件。在實現這些特性的瀏覽器中,XMLHttpRequest對象有一個upload屬性,upload屬性值是一個對象,它定義了addEventListener()方法和整個progress事件集合,比如onprogress和onload。
```
xhr.upload.onprogress = function(e){
var percentComplete = e.loaded / e.total;
}
```
**3.3 中止請求和超時**
我們可以通過調用XMLHttpRequest對象的abort()方法來取消正在進行的HTTP請求,調用abort()方法時,會觸發abort事件。
在XHR2中,還定義了timeout屬性來指定自動中止后的毫秒數。
```
xhr.timeout = 1000;
```
**4、同源策略**
同源策略是對JavaScript代碼能夠操作哪些Web內容的一條完整的安全限制。當Web頁面使用多個`<iframe>`元素或打開其他瀏覽器窗口的時候,這一策略通常就會發揮作用。
所謂“同源”指的是”三個相同“。
- 協議相同
- 域名相同
- 端口相同
從不同Web服務器載入的文檔具有不同的來源。通過同一主機的不同端口載入的文檔具有不同的來源。使用http:協議載入的文檔和使用https:協議載入的文檔具有不同的來源,即使它們來自同一個服務器。
同源政策的目的,是為了保證用戶信息的安全,防止惡意的網站竊取數據。
**4.1 不嚴格的同源策略**
有三種不嚴格的同源策略
**(1)使用Document對象的domain屬性**
在默認情況下,屬性domain存放的是載入文檔的服務器的主機名。
比如:來自home.example.com的文檔里的腳本要合法的讀取developer.example.com載入的文檔的屬性(默認情況下是不允許的,會受到同源策略的限制)。
```
document.domain = 'example.com';
```
一旦上面兩個文檔里包含的腳本把domain都設置成了上面相同的值,那么這兩個文檔就不會受同源策略的約束了,可以相互讀取對方的屬性。
**(2)跨域資源共享(Cross-Origin Resource Sharing)**
這種方式是應用到后臺中:
```
Access-Control-Allow-Origin:*,//允許所有域名的腳本訪問該資源。
Access-Control-Allow-Origin:http://www.example.com //允許特定的域名訪問。
```
**(3)跨文檔消息(cross-document messaging)**
跨文檔消息允許來自一個文檔的腳本可以傳遞文本消息到另一個文檔里的腳本。
**4.2 跨站腳本**
跨站腳本(Cross-site scripting,XSS),這個術語用來表示一類安全問題,也就是攻擊者向目標Web站點注入HTML標簽或腳本。
通常,防止XSS攻擊的方式是,在使用任何不可信的數據來動態的創建文檔內容之前,從中移除HTML標簽。
**5、Fetch API**
Fetch API是一種新規范,用來取代XMLHttpRequest對象。
**5.1 特性檢測**
```
if(self.fetch){
//支持
}else{
//不支持
}
```
在Fetch API中,最常用的就是fetch()函數,它接收一個URL參數(也可以是request對象),返回一個promise來處理response。response參數還帶著一個Response對象。
```
fetch(url).then(function(response){
console.log(response);
});
```
fetch方法還可以設置第二個參數,用來配置其他值,可選的參數有:
- method: 請求使用的方法,如 GET、POST。
- headers: 請求的頭信息,形式為 Headers 對象或 ByteString。
- body: 請求的 body 信息:可能是一個 Blob、BufferSource、FormData、URLSearchPara ms 或者 USVString 對象。注意 GET 或 HEAD 方法的請求不能包含 body 信息。
- mode: 請求的模式,如 cors、 no-cors 或者 same-origin。
- credentials: 請求的 credentials,如 omit、same-origin 或者 include。
- cache: 請求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.
下面是發出POST請求
```
fetch(url,{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'name=TG&love=1'
}).then(function(response){})
```
注意:fetch() 方法的參數與 Request() 構造器是一樣的。
```
fetch(input, init).then(function(response) { ... });
var myRequest = new Request(input, init);
```
下面是一個Fetch API完整請求的簡單例子:
```
fetch(url).then(function (response) {
return response.json();
}).then(function (jsonData) {
console.log(jsonData);
}).catch(function () {
console.log('出錯了');
});
```
上面代碼向指定的URL發出請求,得到回應后,將其轉為JSON格式,輸出到控制臺。如果出錯,則輸出一條提示信息。
Fetch API引入三個新的對象(也是構造函數):Headers, Request和Response。
**5.2 Headers**
Headers對象用來構造/讀取HTTP數據包的頭信息。
```
reqHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
```
我們還可以使用append方法:
```
var content = 'Hello World';
var headers = new Headers();
headers.append("Accept", "application/json");
headers.append("Content-Type", "text/plain");
headers.append("Content-Length", content.length.toString());
headers.append("X-Custom-Header", "ProcessThisImmediately");
Headers對象實例還提供了一些方法:
reqHeaders.has("Content-Type") // true
reqHeaders.has("Set-Cookie") // false
reqHeaders.set("Content-Type", "text/html")
reqHeaders.append("X-Custom-Header", "AnotherValue")
reqHeaders.get("Content-Length") // 11
reqHeaders.getAll("X-Custom-Header") // ["ProcessThisImmediately", "AnotherValue"]
reqHeaders.delete("X-Custom-Header")
reqHeaders.getAll("X-Custom-Header") // []
```
生成Header實例以后,可以將它作為第二個參數,傳入Request方法。
```
var headers = new Headers();
headers.append('Accept', 'application/json');
var request = new Request(URL, {headers: headers});
fetch(request).then(function(response) {
console.log(response.headers);
});
```
**5.3 Request對象**
Request對象用來構造HTTP請求。
```
var req = new Request("/index.html");
req.method // "GET"
req.url // "http://example.com/index.html"
```
Request對象的第二個參數,表示配置對象,
```
var uploadReq = new Request("/uploadImage", {
method: "POST",
headers: {
"Content-Type": "image/png",
},
body: "image data"
});
```
Request對象實例的mode屬性,用來設置是否跨域,合法的值有以下三種:same-origin、no-cors(默認值)、cors。當設置為same-origin時,只能向同域的URL發出請求,否則會報錯。
**5.4 Response對象**
Fetch API 的Response接口呈現了對一次請求的響應數據
**5.4.1 屬性**
**(1)ok**
如果ok屬性返回的狀態碼在200到299之間(即請求成功),這個屬性為true,否則為false。因此,我們可以這樣判斷請求是否成功:
```
fetch(url).then(function(response){
if(response.ok){
//請求成功
}else{
//請求失敗
}
});
```
**(2)status、statusText**
status屬性返回HTTP的狀態碼;statusText返回一個字符串,表示服務器發送的狀態提示。比如通信成功時,status是200,而statusText是“OK”
**(3)url**
返回完整的請求地址
**(4)type**
type屬性表示HTTP回應的類型。合法的值有五個basic、cors、default、error、opaque。basic表示正常的同域請求;cors表示CORS機制的跨域請求;error表示網絡出錯,無法取得信息,status屬性為0,
如果需要在CORS機制下發出跨域請求,需要指明狀態。
```
fetch(url,{mode: 'cors'}).then(function(response){})
```
**(5)headers**
Headers對象,表示HTTP回應的頭信息
**(6)body**
表示請求的內容。
Request對象和Response對象都有body屬性,表示請求的內容。body屬性可能是以下的數據類型。
```
ArrayBuffer
ArrayBufferView (Uint8Array等)
Blob/File
string
URLSearchParams
FormData
```
注意:上面這些方法都只能使用一次,第二次使用就會報錯,也就是說,body屬性只能讀取一次。Request對象和Response對象都有bodyUsed屬性,返回一個布爾值,表示body是否被讀取過。
如果希望多次使用body屬性,可以使用Response對象和Request對象的clone方法。它必須在body還沒有讀取前調用,返回一個新的body,也就是說,需要使用幾次body,就要調用幾次clone方法。
response.clone()
**(7)bodyUsed**
bodyUsed屬性,返回一個布爾值,表示body是否被讀取過。
**5.4.2 Response對象的方法**
**(1)text()、json()、FormData()、blob()、arrayBuffer()**
在Fetch API中,數據傳送是以數據流(stream)的形式進行的。對于大文件,數據是一段一段得到的。
而Fetch API提供了五個數據流讀取器。
```
text():返回字符串
json():返回一個JSON對象
formData():返回一個FormData對象
blob():返回一個blob對象
arrayBuffer():返回一個二進制數組
```
簡單例子:
```
response.json().then(function(json){
console.log(json);
})
```
- 前言
- JavaScript簡介
- 基本概念
- 語法
- 數據類型
- 運算符
- 表達式
- 語句
- 對象
- 數組
- 函數
- 引用類型(對象)
- Object對象
- Array對象
- Date對象
- RegExp對象
- 基本包裝類型(Boolean、Number、String)
- 單體內置對象(Global、Math)
- console對象
- DOM
- DOM-屬性和CSS
- BOM
- Event 事件
- 正則表達式
- JSON
- AJAX
- 表單和富文本編輯器
- 表單
- 富文本編輯器
- canvas
- 離線應用
- 客戶端存儲(Cookie、Storage、IndexedDB)
- HTML5 API
- Video/Audio
- Geolocation API
- requestAnimationFrame
- File API
- FullScreen API
- IndexedDB
- 檢測設備方向
- Blob
- vibrate
- Luminosity API
- WebRTC
- Page Visibility API
- Performance API
- Web Speech
- Notification
- 面向對象的程序設計
- 概述
- this關鍵字
- 原型鏈
- 作用域
- 常用API合集
- SVG
- 錯誤處理機制
- JavaScript開發技巧合集
- 編程風格
- 垃圾回收機制