瀏覽器與服務器之間,采用HTTP協議通信。用戶在瀏覽器地址欄鍵入一個網址,或者通過網頁表單向服務器提交內容,這時瀏覽器就會向服務器發出HTTP請求。
1999年,微軟公司發布IE瀏覽器5.0版,第一次引入新功能:允許JavaScript腳本向服務器發起HTTP請求。這個功能當時并沒有引起注意,直到2004年Gmail發布和2005年Google Map發布,才引起廣泛重視。2005年2月,AJAX這個詞第一次正式提出,指圍繞這個功能進行開發的一整套做法。從此,AJAX成為腳本發起HTTP通信的代名詞,W3C也在2006年發布了它的國際標準。
具體來說,AJAX包括以下幾個步驟。
- 創建AJAX對象
- 發出HTTP請求
- 接收服務器傳回的數據
- 更新網頁數據
概括起來,就是一句話,AJAX通過原生的XMLHttpRequest
對象發出HTTP請求,得到服務器返回的數據后,再進行處理。
AJAX可以是同步請求,也可以是異步請求。但是,大多數情況下,特指異步請求。因為同步的Ajax請求,對瀏覽器有“堵塞效應”。
XMLHttpRequest對象
XMLHttpRequest
對象用來在瀏覽器與服務器之間傳送數據。
var ajax = new XMLHttpRequest();
ajax.open('GET', 'http://www.example.com/page.php', true);
上面代碼向指定的服務器網址,發出GET請求。
然后,AJAX指定回調函數,監聽通信狀態(readyState
屬性)的變化。
ajax.onreadystatechange = handleStateChange;
一旦拿到服務器返回的數據,AJAX不會刷新整個網頁,而是只更新相關部分,從而不打斷用戶正在做的事情。
注意,AJAX只能向同源網址(協議、域名、端口都相同)發出HTTP請求,如果發出跨源請求,就會報錯(詳見《同源政策》和《CORS機制》兩節)。
雖然名字里面有XML
,但是實際上,XMLHttpRequest可以報送各種數據,包括字符串和二進制,而且除了HTTP,它還支持通過其他協議傳送(比如File和FTP)。
下面是XMLHttpRequest
對象的典型用法。
var xhr = new XMLHttpRequest();
// 指定通信過程中狀態改變時的回調函數
xhr.onreadystatechange = function(){
// 通信成功時,狀態值為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);
};
// open方式用于指定HTTP動詞、請求的網址、是否異步
xhr.open('GET', '/endpoint', true);
// 發送HTTP請求
xhr.send(null);
open
方法的第三個參數是一個布爾值,表示是否為異步請求。如果設為false
,就表示這個請求是同步的,下面是一個例子。
var request = new XMLHttpRequest();
request.open('GET', '/bar/foo.txt', false);
request.send(null);
if (request.status === 200) {
console.log(request.responseText);
}
XMLHttpRequest實例的屬性
readyState
readyState
是一個只讀屬性,用一個整數和對應的常量,表示XMLHttpRequest請求當前所處的狀態。
- 0,對應常量
UNSENT
,表示XMLHttpRequest實例已經生成,但是open()
方法還沒有被調用。 - 1,對應常量
OPENED
,表示send()
方法還沒有被調用,仍然可以使用setRequestHeader()
,設定HTTP請求的頭信息。 - 2,對應常量
HEADERS_RECEIVED
,表示send()
方法已經執行,并且頭信息和狀態碼已經收到。 - 3,對應常量
LOADING
,表示正在接收服務器傳來的body部分的數據,如果responseType
屬性是text
或者空字符串,responseText
就會包含已經收到的部分信息。 - 4,對應常量
DONE
,表示服務器數據已經完全接收,或者本次接收已經失敗了。
在通信過程中,每當發生狀態變化的時候,readyState
屬性的值就會發生改變。這個值每一次變化,都會觸發readyStateChange
事件。
if (ajax.readyState == 4) {
// Handle the response.
} else {
// Show the 'Loading...' message or do nothing.
}
上面代碼表示,只有readyState
變為4時,才算確認請求已經成功,其他值都表示請求還在進行中。
onreadystatechange
onreadystatechange
屬性指向一個回調函數,當readystatechange
事件發生的時候,這個回調函數就會調用,并且XMLHttpRequest實例的readyState
屬性也會發生變化。
另外,如果使用abort()
方法,終止XMLHttpRequest請求,onreadystatechange
回調函數也會被調用。
var xmlhttp = new XMLHttpRequest();
xmlhttp.open( 'GET', 'http://example.com' , true );
xmlhttp.onreadystatechange = function () {
if ( XMLHttpRequest.DONE != xmlhttp.readyState ) {
return;
}
if ( 200 != xmlhttp.status ) {
return;
}
console.log( xmlhttp.responseText );
};
xmlhttp.send();
response
response
屬性為只讀,返回接收到的數據體(即body部分)。它的類型可以是ArrayBuffer、Blob、Document、JSON對象、或者一個字符串,這由XMLHttpRequest.responseType
屬性的值決定。
如果本次請求沒有成功或者數據不完整,該屬性就會等于null
。
responseType
responseType
屬性用來指定服務器返回數據(xhr.response
)的類型。
- ”“:字符串(默認值)
- “arraybuffer”:ArrayBuffer對象
- “blob”:Blob對象
- “document”:Document對象
- “json”:JSON對象
- “text”:字符串
text類型適合大多數情況,而且直接處理文本也比較方便,document類型適合返回XML文檔的情況,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([this.response], {type: 'image/png'});
// 或者
var blob = oReq.response;
}
};
xhr.send();
如果將這個屬性設為ArrayBuffer,就可以按照數組的方式處理二進制數據。
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 = binStr.length; i < len; ++i) {
// var byte = uInt8Array[i];
}
};
xhr.send();
如果將這個屬性設為“json”,支持JSON的瀏覽器(Firefox>9,chrome>30),就會自動對返回數據調用JSON.parse()
方法。也就是說,你從xhr.response屬性(注意,不是xhr.responseText屬性)得到的不是文本,而是一個JSON對象。
XHR2支持Ajax的返回類型為文檔,即xhr.responseType=”document” 。這意味著,對于那些打開CORS的網站,我們可以直接用Ajax抓取網頁,然后不用解析HTML字符串,直接對XHR回應進行DOM操作。
responseText
responseText
屬性返回從服務器接收到的字符串,該屬性為只讀。如果本次請求沒有成功或者數據不完整,該屬性就會等于null
。
如果服務器返回的數據格式是JSON,就可以使用responseText
屬性。
var data = ajax.responseText;
data = JSON.parse(data);
responseXML
responseXML
屬性返回從服務器接收到的Document對象,該屬性為只讀。如果本次請求沒有成功,或者數據不完整,或者不能被解析為XML或HTML,該屬性等于null
。
返回的數據會被直接解析為DOM對象。
/* 返回的XML文件如下
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<book>
<chapter id="1">(Re-)Introducing JavaScript</chapter>
<chapter id="2">JavaScript in Action</chapter>
</book>
*/
var data = ajax.responseXML;
var chapters = data.getElementsByTagName('chapter');
如果服務器返回的數據,沒有明示Content-Type
頭信息等于text/xml
,可以使用overrideMimeType()
方法,指定XMLHttpRequest對象將返回的數據解析為XML。
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,服務器發生錯誤
基本上,只有2xx和304的狀態碼,表示服務器返回是正常狀態。
if (ajax.readyState == 4) {
if ( (ajax.status >= 200 && ajax.status < 300)
|| (ajax.status == 304) ) {
// Handle the response.
} else {
// Status error!
}
}
statusText
statusText
屬性為只讀屬性,返回一個字符串,表示服務器發送的狀態提示。不同于status
屬性,該屬性包含整個狀態信息,比如”200 OK“。
timeout
timeout
屬性等于一個整數,表示多少毫秒后,如果請求仍然沒有得到結果,就會自動終止。如果該屬性等于0,就表示沒有時間限制。
var xhr = new XMLHttpRequest();
xhr.ontimeout = function () {
console.error("The request for " + url + " timed out.");
};
xhr.onload = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
callback.apply(xhr, args);
} else {
console.error(xhr.statusText);
}
}
};
xhr.open("GET", url, true);
xhr.timeout = timeout;
xhr.send(null);
}
事件監聽接口
XMLHttpRequest第一版,只能對onreadystatechange
這一個事件指定回調函數。該事件對所有情況作出響應。 XMLHttpRequest第二版允許對更多的事件指定回調函數。
- onloadstart 請求發出
- onprogress 正在發送和加載數據
- onabort 請求被中止,比如用戶調用了
abort()
方法 - onerror 請求失敗
- onload 請求成功完成
- ontimeout 用戶指定的時限到期,請求還未完成
- onloadend 請求完成,不管成果或失敗
xhr.onload = function() {
var responseText = xhr.responseText;
console.log(responseText);
// process the response.
};
xhr.onerror = function() {
console.log('There was an error!');
};
注意,如果發生網絡錯誤(比如服務器無法連通),onerror
事件無法獲取報錯信息,所以只能顯示報錯。
withCredentials
withCredentials
屬性是一個布爾值,表示跨域請求時,用戶信息(比如Cookie和認證的HTTP頭信息)是否會包含在請求之中,默認為false
。即向[example.com](http://example.com/)
發出跨域請求時,不會發送[example.com](http://example.com/)
設置在本機上的Cookie(如果有的話)。
如果你需要通過跨域AJAX發送Cookie,需要打開withCredentials
。
xhr.withCredentials = true;
為了讓這個屬性生效,服務器必須顯式返回Access-Control-Allow-Credentials
這個頭信息。
Access-Control-Allow-Credentials: true
.withCredentials
屬性打開的話,不僅會發送Cookie,還會設置遠程主機指定的Cookie。注意,此時你的腳本還是遵守同源政策,無法 從document.cookie
或者HTTP回應的頭信息之中,讀取這些Cookie。
XMLHttpRequest實例的方法
abort()
abort
方法用來終止已經發出的HTTP請求。
ajax.open('GET', 'http://www.example.com/page.php', true);
var ajaxAbortTimer = setTimeout(function() {
if (ajax) {
ajax.abort();
ajax = null;
}
}, 5000);
上面代碼在發出5秒之后,終止一個AJAX請求。
getAllResponseHeaders()
getAllResponseHeaders
方法返回服務器發來的所有HTTP頭信息。格式為字符串,每個頭信息之間使用CRLF
分隔,如果沒有受到服務器回應,該屬性返回null
。
getResponseHeader()
getResponseHeader
方法返回HTTP頭信息指定字段的值,如果還沒有收到服務器回應或者指定字段不存在,則該屬性為null
。
function getHeaderTime () {
console.log(this.getResponseHeader("Last-Modified"));
}
var oReq = new XMLHttpRequest();
oReq.open("HEAD", "yourpage.html");
oReq.onload = getHeaderTime;
oReq.send();
如果有多個字段同名,則它們的值會被連接為一個字符串,每個字段之間使用“逗號+空格”分隔。
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
:表示用于認證的密碼,默認為空字符串。
如果對使用過open()
方法的請求,再次使用這個方法,等同于調用abort()
。
下面發送POST請求的例子。
xhr.open('POST', encodeURI('someURL'));
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {};
xhr.send(encodeURI('dataString'));
上面方法中,open方法向指定URL發出POST請求,send方法送出實際的數據。
下面是一個同步AJAX請求的例子。
var request = new XMLHttpRequest();
request.open('GET', '/bar/foo.txt', false);
request.send(null);
if (request.status === 200) {
console.log(request.responseText);
}
send()
send
方法用于實際發出HTTP請求。如果不帶參數,就表示HTTP請求只包含頭信息,也就是只有一個URL,典型例子就是GET請求;如果帶有參數,就表示除了頭信息,還帶有包含具體數據的信息體,典型例子就是POST請求。
ajax.open('GET'
, 'http://www.example.com/somepage.php?id=' + encodeURIComponent(id)
, true
);
// 等同于
var data = 'id=' + encodeURIComponent(id));
ajax.open('GET', 'http://www.example.com/somepage.php', true);
ajax.send(data);
上面代碼中,GET
請求的參數,可以作為查詢字符串附加在URL后面,也可以作為send
方法的參數。
下面是發送POST請求的例子。
var data = 'email='
+ encodeURIComponent(email)
+ '&password='
+ encodeURIComponent(password);
ajax.open('POST', 'http://www.example.com/somepage.php', true);
ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
ajax.send(data);
如果請求是異步的(默認為異步),該方法在發出請求后會立即返回。如果請求為同步,該方法只有等到收到服務器回應后,才會返回。
注意,所有XMLHttpRequest的監聽事件,都必須在send()
方法調用之前設定。
send
方法的參數就是發送的數據。多種格式的數據,都可以作為它的參數。
void send();
void send(ArrayBufferView data);
void send(Blob data);
void send(Document data);
void send(String data);
void send(FormData data);
如果發送Document
數據,在發送之前,數據會先被串行化。
發送二進制數據,最好使用ArrayBufferView
或Blob
對象,這使得通過Ajax上傳文件成為可能。
下面是一個上傳ArrayBuffer
對象的例子。
function sendArrayBuffer() {
var xhr = new XMLHttpRequest();
var uInt8Array = new Uint8Array([1, 2, 3]);
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(uInt8Array.buffer);
}
FormData類型可以用于構造表單數據。
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);
上面的代碼構造了一個formData
對象,然后使用send方法發送。它的效果與點擊下面表單的submit按鈕是一樣的。
<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也可以將現有表單構造生成。
var formElement = document.querySelector("form");
var request = new XMLHttpRequest();
request.open("POST", "submitform.php");
request.send(new FormData(formElement));
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(e) {
// ...
};
xhr.send(formData);
return false;
}
var form = document.querySelector('#registration');
sendForm(form);
FormData對象也能用來模擬File控件,進行文件上傳。
function uploadFiles(url, files) {
var formData = new FormData();
for (var i = 0, file; file = files[i]; ++i) {
formData.append(file.name, file); // 可加入第三個參數,表示文件名
}
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onload = function(e) { ... };
xhr.send(formData); // multipart/form-data
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
uploadFiles('/server', this.files);
}, false);
FormData也可以加入JavaScript生成的文件。
// 添加JavaScript生成的文件
var content = '<a id="a"><b id="b">hey!</b></a>';
var blob = new Blob([content], { type: "text/xml"});
formData.append("webmasterfile", blob);
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數據。
overrideMimeType()
該方法用來指定服務器返回數據的MIME類型。該方法必須在send()
之前調用。
傳統上,如果希望從服務器取回二進制數據,就要使用這個方法,人為將數據類型偽裝成文本數據。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
// 強制將MIME改為文本類型
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e) {
if (this.readyState == 4 && this.status == 200) {
var binStr = this.responseText;
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
var byte = c & 0xff; // 去除高位字節,留下低位字節
}
}
};
xhr.send();
上面代碼中,因為傳回來的是二進制數據,首先用xhr.overrideMimeType
方法強制改變它的MIME類型,偽裝成文本數據。字符集必需指定為“x-user-defined”,如果是其他字符集,瀏覽器內部會強制轉碼,將其保存成UTF-16的形式。字符集“x-user-defined”其實也會發生轉碼,瀏覽器會在每個字節前面再加上一個字節(0xF700-0xF7ff),因此后面要對每個字符進行一次與運算(&),將高位的8個位去除,只留下低位的8個位,由此逐一讀出原文件二進制數據的每個字節。
這種方法很麻煩,在XMLHttpRequest版本升級以后,一般采用指定responseType
的方法。
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
var arraybuffer = xhr.response;
// ...
}
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.send();
XMLHttpRequest實例的事件
readyStateChange事件
readyState
屬性的值發生改變,就會觸發readyStateChange事件。
我們可以通過onReadyStateChange
屬性,指定這個事件的回調函數,對不同狀態進行不同處理。尤其是當狀態變為4的時候,表示通信成功,這時回調函數就可以處理服務器傳送回來的數據。
progress事件
上傳文件時,XMLHTTPRequest對象的upload屬性有一個progress,會不斷返回上傳的進度。
假定網頁上有一個progress元素。
<progress min="0" max="100" value="0">0% complete</progress>
文件上傳時,對upload屬性指定progress事件回調函數,即可獲得上傳的進度。
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));
load事件、error事件、abort事件
load事件表示服務器傳來的數據接收完畢,error事件表示請求出錯,abort事件表示請求被中斷。
var xhr = new XMLHttpRequest();
xhr.addEventListener("progress", updateProgress);
xhr.addEventListener("load", transferComplete);
xhr.addEventListener("error", transferFailed);
xhr.addEventListener("abort", transferCanceled);
xhr.open();
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = oEvent.loaded / oEvent.total;
// ...
} else {
// 回應的總數據量未知,導致無法計算百分比
}
}
function transferComplete(evt) {
console.log("The transfer is complete.");
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}
loadend事件
abort
、load
和error
這三個事件,會伴隨一個loadend
事件,表示請求結束,但不知道其是否成功。
req.addEventListener("loadend", loadEnd);
function loadEnd(e) {
alert("請求結束(不知道是否成功)");
}
文件上傳
HTML網頁的<form>
元素能夠以四種格式,向服務器發送數據。
- 使用
POST
方法,將enctype
屬性設為application/x-www-form-urlencoded
,這是默認方法。
<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
</form>
- 使用
POST
方法,將enctype
屬性設為text/plain
。
<form action="register.php" method="post" enctype="text/plain" onsubmit="AJAXSubmit(this); return false;">
</form>
- 使用
POST
方法,將enctype
屬性設為multipart/form-data
。
<form action="register.php" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;">
</form>
- 使用
GET
方法,enctype
屬性將被忽略。
<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
</form>
某個表單有兩個字段,分別是foo
和baz
,其中foo
字段的值等于bar
,baz
字段的值一個分為兩行的字符串。上面四種方法,都可以將這個表單發送到服務器。
第一種方法是默認方法,POST發送,Encoding type為application/x-www-form-urlencoded。
Content-Type: application/x-www-form-urlencoded
foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
第二種方法是POST發送,Encoding type為text/plain。
Content-Type: text/plain
foo=bar
baz=The first line.
The second line.
第三種方法是POST發送,Encoding type為multipart/form-data。
Content-Type: multipart/form-data; boundary=---------------------------314911788813839
-----------------------------314911788813839
Content-Disposition: form-data; name="foo"
bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz"
The first line.
The second line.
-----------------------------314911788813839--
第四種方法是GET請求。
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
通常,我們使用file控件實現文件上傳。
<form id="file-form" action="handler.php" method="POST">
<input type="file" id="file-select" name="photos[]" multiple/>
<button type="submit" id="upload-button">上傳</button>
</form>
上面HTML代碼中,file控件的multiple屬性,指定可以一次選擇多個文件;如果沒有這個屬性,則一次只能選擇一個文件。
file對象的files屬性,返回一個FileList對象,包含了用戶選中的文件。
var fileSelect = document.getElementById('file-select');
var files = fileSelect.files;
然后,新建一個FormData對象的實例,用來模擬發送到服務器的表單數據,把選中的文件添加到這個對象上面。
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.type.match('image.*')) {
continue;
}
formData.append('photos[]', file, file.name);
}
上面代碼中的FormData對象的append方法,除了可以添加文件,還可以添加二進制對象(Blob)或者字符串。
// FilesformData.append(name, file, filename);// BlobsformData.append(name, blob, filename);// StringsformData.append(name, value);
append方法的第一個參數是表單的控件名,第二個參數是實際的值,第三個參數是可選的,通常是文件名。
最后,使用Ajax方法向服務器上傳文件。
var xhr = new XMLHttpRequest();xhr.open('POST', 'handler.php', true);xhr.onload = function () { if (xhr.status !== 200) { alert('An error occurred!'); }};xhr.send(formData);
目前,各大瀏覽器(包括IE 10)都支持Ajax上傳文件。
除了使用FormData接口上傳,也可以直接使用File API上傳。
var file = document.getElementById('test-input').files[0];
var xhr = new XMLHttpRequest();
xhr.open('POST', 'myserver/uploads');
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);
可以看到,上面這種寫法比FormData的寫法,要簡單很多。
參考鏈接
MDN, Using XMLHttpRequest
Mathias Bynens, Loading JSON-formatted data with Ajax and xhr.responseType=’json’
Eric Bidelman, New Tricks in XMLHttpRequest2
Matt West, Uploading Files with AJAX
Matt Gaunt, Introduction to fetch()
Nikhil Marathe, This API is so Fetching!
Ludovico Fischer, Introduction to the Fetch API