1. 程式人生 > 其它 >jQuery 利用 FormData 上傳檔案

jQuery 利用 FormData 上傳檔案

檔案上傳是Web開發中的重要話題,最直接和簡單的方式是通過表單直接提交檔案。 Harttle認為,我們引入jQuery來進行非同步上傳可以獲得更好的使用者體驗。 一方面,在JavaScript中進行非同步操作比表單更加靈活; 另一方面,非同步上傳也避免了上傳大檔案時的頁面長時間卡死。

HTML

一個type=file<input>就可以讓使用者來瀏覽並選擇檔案, 一般會把輸入控制元件放到一個<form>中,下面的一個簡單的表單:

<form>
  <input type="file" id="avatar" name="avatar">
  <button type="button">儲存</button>
</form>

但為什麼我只能選擇一個檔案??給<input>新增一個multiple屬性就可以多選了!

<input type="file" id="avatar" name="avatar" multiple>

獲取檔案列表

上述的<input>將會擁有一個叫files的DOM屬性,包含了所選的檔案列表(Array)。

$('button').click(function(){
  var $input = $('#avatar');
  // 相當於: $input[0].files, $input.get(0).files
  var files = $input.prop('files');
  console.log(files);
});

這個Array中的每一項都是一個File物件,它有下面幾個主要屬性:

  • name: 檔名,只讀字串,不包含任何路徑資訊.
  • size: 檔案大小,單位為位元組,只讀的64位整數.
  • type: MIME型別,只讀字串,如果型別未知,則返回空字串.

見:https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications

multipart/form-data

上傳檔案比較特殊,其內容是二進位制資料,而HTTP提供的是基於文字的通訊協議。 這時需要採用multipart/form-data編碼的HTTP表單。其HTTP訊息體格式如下所示:

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="title"

harttle
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="avatar"; filename="harttle.png"
Content-Type: image/png

 ... content of harttle.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

每個欄位由一段boundary string來分隔,瀏覽器保證該boundary string不與內容重複, 因而multipart/form-data能夠成功編碼二進位制資料。

更多關於HTTP表單編碼的細節,請參考:HTTP 表單編碼 enctype

jQuery上傳檔案

這是XMLHttpRequest Level 2提供的FormData物件可以幫助我們進行二進位制檔案的multipart/form-data編碼:

$('button').click(function(){
  var files = $('#avatar').prop('files');

  var data = new FormData();
  data.append('avatar', files[0]);

  $.ajax({
      url: '/api/upload',
      type: 'POST',
      data: data,
      cache: false,
      processData: false,
      contentType: false
  });
});

url,type,data想必做前端的都很熟悉了,介紹其餘三個引數:

cache

cache設為false可以禁止瀏覽器對該URL(以及對應的HTTP方法)的快取。 jQuery通過為URL新增一個冗餘引數來實現。

該方法只對GET和HEAD起作用,然而IE8會快取之前的GET結果來響應POST請求。 這裡設定cache: false是為了相容IE8。

參考:http://api.jquery.com/jquery.ajax/

contentType

jQuery中content-type預設值為application/x-www-form-urlencoded, 因此傳給data引數的物件會預設被轉換為query string(見HTTP 表單編碼 enctype)。

我們不需要jQuery做這個轉換,否則會破壞掉multipart/form-data的編碼格式。 因此設定contentType: false來禁止jQuery的轉換操作。

processData

jQuery會將data物件轉換為字串來發送HTTP請求,預設情況下會用application/x-www-form-urlencoded編碼來進行轉換。 我們設定contentType: false後該轉換會失敗,因此設定processData: false來禁止該轉換過程。

我們給的data就是已經用FormData編碼好的資料,不需要jQuery進行字串轉換。

相容性與其他選擇

本文介紹的jQuery檔案上傳方式依賴於FormData物件, 這是XMLHttpRequest Level 2介面, 需要 IE 10+, Firefox 4.0+, Chrome 7+, Safari 5+, Opera 12+

這意味著對於低版本瀏覽器只能使用直接提交檔案表單的形式, 但提交大檔案表單頁面會長時間不響應,如果希望在低版本瀏覽器中解決該問題, 就只能使用別的方式來實現了,比如很多支援多檔案和上傳進度的Flash外掛。

本文采用知識共享署名 4.0 國際許可協議(CC-BY 4.0)進行許可,轉載註明來源即可:https://harttle.land/2016/07/04/jquery-file-upload.html。學識粗淺寫作倉促,如有錯誤辛苦評論或郵件指出。