文件上傳原理
根據http協議的定義,完成請求消息體的封裝和解析,將二進制內容保存至文件。
關鍵字:
multipart/form-data
含義:
multipart表示資源有多種元素組成,form-data使用post方式或HTML Forms上傳文件。
結構:

- 請求頭:表示本次請求要上傳文件,其中boundary表示分隔符。
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2ahjiirVMKa4Qn78
- 消息體- Form Data 部分
Content-Disposition: form-data 為固定值,表示一個表單元素,name 表示表單元素的 名稱,回車換行后面就是name的值,如果是上傳文件就是文件的二進制內容。
Content-Type:表示當前的內容的 MIME 類型(type/subtype)通用+子類,是圖片還是文本還是二進制數據(text/.. application/... image/... video/...)。
解析:
客戶端發送請求到服務器后,服務器拿到請求的消息體進行解析,解析出哪些是普通表單哪些是附件。一般不需要自行解析,有第三方庫可用。
無刷新上傳
關鍵字:
XMLHttpRequest
XMLHttpRequest2有了升級,首先就是可以讀取和上傳二進制數據,可以使用·FormData·對象管理表單數據。
示例:
<div> 選擇文件(可多選): <input type="file" id="f1" multiple/><br/><br/> <button type="button" id="btn-submit">上 傳</button> </div>
<script>
function submitUpload() {
//獲得文件列表,注意這里不是數組,而是對象
var fileList = document.getElementById('f1').files;
if(!fileList.length){
alert('請選擇文件');
return;
}
var fd = new FormData(); //構造FormData對象
fd.append('title', document.getElementById('title').value);
//多文件上傳需要遍歷添加到 fromdata 對象
for(var i =0;i<fileList.length;i++){
fd.append('f1', fileList[i]);//支持多文件上傳
}
var xhr = new XMLHttpRequest(); //創建對象
xhr.open('POST', 'http://localhost:8100/', true);
xhr.send(fd);//發送時 Content-Type默認就是: multipart/form-data;
xhr.onreadystatechange = function () {
console.log('state change', xhr.readyState);
if (this.readyState == 4 && this.status == 200) {
var obj = JSON.parse(xhr.responseText); //返回值
console.log(obj);
if(obj.fileUrl.length){
alert('上傳成功');
}
}
}
}
//綁定提交事件
document.getElementById('btn-submit').addEventListener('click',submitUpload);
</script>
實現進度條
借助XMLHttpRequest2,實現單文件或多文件的上傳進度條。

說明
- 頁面內增加一個用於顯示進度的標簽
div.progress js內處理增加進度處理的監聽函數xhr.upload.onprogressevent.lengthComputable這是一個狀態,表示發送的長度有了變化,可計算event.loaded表示發送了多少字節event.total表示文件總大小- 根據
event.loaded和event.total計算進度,渲染div.progress
<div> 選擇文件(可多選): <input type="file" id="f1" multiple/><br/><br/> <div id="progress"> <span class="red"></span> </div> <button type="button" id="btn-submit">上 傳</button> </div>
<script>
function submitUpload() {
var progressSpan = document.getElementById('progress').firstElementChild;
var fileList = document.getElementById('f1').files;
progressSpan.style.width='0';
progressSpan.classList.remove('green');
if(!fileList.length){
alert('請選擇文件');
return;
}
var fd = new FormData(); //構造FormData對象
fd.append('title', document.getElementById('title').value);
for(var i =0;i<fileList.length;i++){
fd.append('f1', fileList[i]);//支持多文件上傳
}
var xhr = new XMLHttpRequest(); //創建對象
xhr.open('POST', 'http://10.70.65.235:8100/', true);
xhr.onreadystatechange = function () {
console.log('state change', xhr.readyState);
if (xhr.readyState == 4) {
var obj = JSON.parse(xhr.responseText); //返回值
console.log(obj);
if(obj.fileUrl.length){
//alert('上傳成功');
}
}
}
xhr.onprogress=updateProgress;
xhr.upload.onprogress = updateProgress;
function updateProgress(event) {
console.log(event);
if (event.lengthComputable) {
var completedPercent = (event.loaded / event.total * 100).toFixed(2);
progressSpan.style.width= completedPercent+'%';
progressSpan.innerHTML=completedPercent+'%';
if(completedPercent>90){//進度條變色
progressSpan.classList.add('green');
}
console.log('已上傳',completedPercent);
}
}
//注意 send 一定要寫在最下面,否則 onprogress 只會執行最后一次 也就是100%的時候
xhr.send(fd);//發送時 Content-Type默認就是: multipart/form-data;
}
//綁定提交事件
document.getElementById('btn-submit').addEventListener('click',submitUpload);
</script>
PS 特別提醒
xhr.upload.onprogress要寫在xhr.send方法前面,否則event.lengthComputable狀態不會改變,只有在最后一次才能獲得,也就是100%的時候.
