HTML5關于上傳API的一些使用(上)
HTML5提供了很多有用的API,其中就包括上傳的API,XMLHttpRequest2.0,在HTML5時代之前,需要進行二進制的上傳一般都會才用flash的方案,但是當XMLHttpRequest2.0出來之后,完全可以使用HTML5的上傳解決方案,能夠非常方便的進行二進制上傳進度的顯示,上傳圖片的本地預覽,甚至可以做到斷點續傳,分片上傳,多文件上傳等各種復雜的底層功能。
首先回顧一下XMLHttpRequest1.0的傳輸過程
關于XMLHttpRequest
初始化XMLHttpRequest
想要使用XMLHttpRequest進行傳輸文件,首先我們得創建一個XMLHttpRequest對象, 而 每創建一個XMLHttpRequest的時候會產生readyState這個屬性 ,當一個 XMLHttpRequest 初次創建時,這個屬性的值從 0 開始,直到接收到完整的 HTTP 響應,這個值增加到 4。 5 個狀態中每一個都有一個相關聯的非正式的名稱,下表列出了狀態、名稱和含義:
狀態 名稱 描述
0 Uninitialized 初始化狀態。XMLHttpRequest 對象已創建或已被 abort() 方法重置。
1 Open open() 方法已調用,但是 send() 方法未調用。請求還沒有被發送。
2 Sent Send() 方法已調用,HTTP 請求已發送到 Web 服務器。未接收到響應。
3 Receiving 所有響應頭部都已經接收到。響應體開始接收但未完成。
4 Loaded HTTP 響應已經完全接收。
var xhr = new XMLHttpRequest(); //readyState為0
xhr.open方法設置初始參數
然后需要初始化一些HTTP請求的參數但是這里只是初始化,也就是說設置一些上傳所需要的參數,但是并不會進行上傳
xhr.open(method, url, async, username, password); //readyState為1
method 參數是用于請求的 HTTP 方法。值包括 GET、POST 和 HEAD。
url 參數是請求的主體。大多數瀏覽器實施了一個同源安全策略,并且要求這個 URL 與包含腳本的文本具有相同的主機名和端口。
async 參數指示請求使用應該異步地執行。如果這個參數是 false,請求是同步的,后續對 send() 的調用將阻塞,直到響應完全接收。如果這個參數是 true 或省略,請求是異步的,且通常需要一個 onreadystatechange 事件句柄。
username 和 password 參數是可選的,為 url 所需的授權提供認證資格。如果指定了,它們會覆蓋 url 自己指定的任何資格。
xhr.send()方法發送請求
對HTTP的請求的參數設置完之后就可以進行發送了
xhr.send(); //readyState為2
xhr.send()會導致一個HTTP請求。如果之前沒有調用 open()或者說 readyState 不是 1,xhr.send() 則會跑出一個錯誤。否則,它發送一個 HTTP 請求,該請求由以下幾部分組成: 之前調用xhr.open() 時指定的 HTTP 方法、URL 以及認證資格(如果有的話)。 之前調用 xhr.setRequestHeader() 時指定的請求頭部(如果有的話)。 傳遞給這個方法的 body 參數。
請求發布后,send() 把 readyState 設置為 2,并觸發 onreadystatechange 事件。
關于 onreadystatechange 事件
onreadystatechange實際上是每當readyState發生改變的時候就會觸發的參數,也就是說我們可以直接在onreadystatechange事件中去判斷readyState的值,假如readyState等于4的時候就可以執行上傳完成后的回調方法。
如果之前調用的xhr.open() 參數 async 為 false,這個方法會阻塞并不會返回,直到 readyState 為 4 并且服務器的響應被完全接收。否則,如果 async 參數為 true,或者這個參數省略了,xhr.send() 立即返回。如果服務器響應帶有一個 HTTP 重定向,xhr.send() 方法或后臺線程自動遵從重定向。當所有的 HTTP 響應頭部已經接收,xhr.send() 或后臺線程把 readyState 設置為 3 并觸發 onreadystatechange 事件句柄。如果響應較長,xhr.send() 或后臺線程可能在狀態 3 中觸發 onreadystatechange 事件句柄:這可以作為一個下載進度指示器。最后,當響應完成,xhr.send() 或后臺線程把 readyState 設置為 4,并最后一次觸發事件句柄。
通過上面的初始化,open,send,已經監控onreadystatechange事件的返回值用以觸發回調方法,我們就完成了一個ajax請求。
關于XMLHttpRequest2.0
而關于HTML5中增加XMLHttpRequest2.0的新功能主要包括下面這些:
- 可以設置HTTP請求的時限。
- 可以使用FormData對象管理表單數據。
- 可以上傳文件。
- 可以請求不同域名下的數據(跨域請求)。
- 可以獲取服務器端的二進制數據。
- 可以獲得數據傳輸的進度信息。
我們這里主要說和上傳文件比較密切相關的部分
關于FormData
AJAX通常可以用來進行模擬表單的提交,也就是說XMLHttpRequest1.0中大家經常使用的無刷新提交數據,為了方便對于表單的處理,HTML新增了一個FormData對象,可以用來模擬表單。使用如下:
var formData=new FormData(); formData.append('name',"Jack"); formData.append('uid',666666);
上面的三行代碼就實現了往一個FormData()對象里面插入了兩個字段,一個name,一個uid 然后我們可以就像XMLHttpRequest1.0的時候一樣進行ajax的提交即:
var xhr=new XMLHttpRequest(); xhr.open("post",url); xhr.send(formData);
關于HTML5多文件的上傳
那我們實際上想要用HTML5解決上傳文件的過程應該怎么解決呢? HTML5中針對 <input type="file"/> 標簽新加了一個files的對象,并且通過對input標簽設置multiple屬性,則可以實現添加多個文件的功能,而files實際上是一個數組對象,里面存的則全是這個file標簽中的文件;
那么我們想要上傳文件就很簡單了, 直接循環files對象獲取到用戶添加到file控件中的文件并且都通過FormData對象的append方法添加到FormData中去,然后進行發送即可。
var formData=new FormData(); for(var i=0;i<files.length;i++){ formData.append(i,files[i]); } var xhr=new XMLHttpRequest(); xhr.open("post",url); xhr.send(formData);
通過上面這些代碼就可以實現對于多文件的上傳了。
關于HTML5上傳中的各種需求
雖然上面實現了對于多個文件的上傳,但是大家在實際工作中對于上傳的需求肯定不單單是能夠上傳而已,下面我們就來說下利用HTML5對于上傳API中新增加的一大堆好用的東西所能夠實現的效果;
上傳之前的本地預覽
大家在做文件上傳之前,經常會碰到需要預覽文件大小,文件名稱等信息,關于這些HTML5已經幫我們封裝好了相應的API,我們只需要調用方法即可 上面說到關于 <input type="file" /> 標簽中有一個files數組對象,實際上這個數組對象中的每一個值都有一些相應的屬性可以調用
- name – 文件名(不包含路徑)
- type – 文件的MIME類型(小寫)
- size – 文件的尺寸(單位為字節)
通過調用上面的三個屬性就可以獲得每一個文件在本地的一些相關信息,相關方法如下
function fileSelected() { var file = document.getElementById('fileToUpload').files[0]; //獲取到上傳控件對象files if (file) { var fileSize = 0; if (file.size > 1024 * 1024){ fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB'; }else{ fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB'; } document.getElementById('fileName').innerHTML = 'Name: ' + file.name; document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize; document.getElementById('fileType').innerHTML = 'Type: ' + file.type; } }
關于FileReader
關于本地的預覽,一些文件的相關信息我們都已經可以拿到了,但是假如我想要上傳的是一張圖片,想要直接本地預覽這張圖片能不能直接在本地完成呢?答案是可以的,只需要你掌握FileReader這個對象即可
FileReader對象一共有4個方法,其中3個可以讀取文件,另一個用來中斷讀取。無論讀取成功或失敗,方法并不會返回讀取結果,這一結果存儲在result屬性中。 4個方法分別是:
- readAsBinaryString(file) 將文件讀取為二進制編碼
- readAsText(file,[encoding]) 將文件讀取為文本
- readAsDataURL(file) 將文件讀取為DataURL
- abort 中斷讀取操作
FileReader對象同樣也有很多事件,分別是:
- onabort 中斷
- onerror 出錯
- onloadstart 開始
- onprogress 正在讀取
- onload 成功讀取
- onloadend 讀取完成,無論成功失敗
那我們在上面的事件方法基礎上就可以實現關于本地預覽圖片的相關方法:
var reader = new FileReader(); //創建一個FileReader對象 reader.readAsDataURL(file); //將文件以Data URL形式讀入頁面 ,并且將結果存在result屬性中 reader.onload=function(e){ //當文件成功讀取后 var imgBox=document.getElementById("imgBox"); imgBox.innerHTML='<img src="' + this.result +'" alt="" />'; //顯示文件 }
通過上面的方法就可以實現圖片的本地預覽了,當然上面那個方法還可以結合之前的files對象中的type,size等屬性實現上傳圖片類型大小的限制。
關于HTML5的上傳部分,實際上還有很多應用的地方,將會在以后的博客中告訴大家。