web 文件上傳的幾種方式

問題

文件上傳在WEB開發中應用很普遍。javascript

文件上傳是指將本地圖片、視頻、音頻等文件上傳到服務器上,能夠供其餘用戶瀏覽或下載的過程。html

如下總結了常見的文件(圖片)上傳的方式和要點處理。前端

表單上傳

這是傳統的form表單上傳,使用form表單的input[type=」file」]控件,能夠打開系統的文件選擇對話框,從而達到選擇文件並上傳的目的,它的好處是多瀏覽器兼容,它是web開發者最經常使用的一種文件上傳方式。html5

表單的代碼以下:java

<form method="post" action="http://uploadUrl" enctype="multipart/form-data">
    <input name="file" type="file" accept="image/gif,image.jpg" />
    <input name="token" type="hidden" />
    <input type="submit" value="提交" /> 
</form>

 

如下是表單上傳幾個關鍵點:android

method="post": 採用post方式提交數據
enctype="multipart/form- data":採用multipart格式上傳文件,此時request頭會顯示 Content-Type:multipart/form-data; boundary=—-WebKitFormBoundaryzr34cwJ67R95KQC9
action:標明上傳的服務端處理地址
type="file":使用input的file控件上傳
若是是多文件批量上傳,能夠將input[type=」file」]的name屬性設置爲如:name=」file[]」
accept屬性是HTML5的新屬性,它規定了可經過文件
上傳提交的文件類型ios

上傳的觸發事件能夠是:input[type=」file」]的onChange觸發,也能夠由一個獨立的按鈕的onClick使整個表單提交,此時還能夠用input[type="hidden"]帶一些其它的參數,好比Token來源驗證等等。web

Ajax無刷新上傳

Ajax無刷新上傳的方式,本質上與表單上傳無異,只是把表單裏的內容提出來採用ajax提交,而且由前端決定請求結果回傳後的展現結果,不用像直接表單上傳那樣刷新和跳轉頁面。在這裏,咱們採用jQuery來做爲操做DOM和建立ajax提交的js基礎庫。ajax

html代碼片斷以下:windows

1
2
3
4
< form >
     < input  id="file" name="file" type="file" />
     < input  id="token" name="token" type="hidden" />
</ form >

 

javascript代碼片斷以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$( "#file" ).on( "change" function (){
   var  formData =  new  FormData();
   formData.append( "file" , $( "#file" )[0].files);
   formData.append( "token" , $( "#token" ).val());
   $.ajax({
       url:  "http://uploadUrl" ,
       type:  "POST" ,
       data: formData,
       processData:  false ,
       contentType:  false ,
       success:  function (response){
               // 根據返回結果指定界面操做
       }
   });
});

 

咱們使用了file控件的change來觸發上傳事件,固然你也可使用某個按鈕來觸發表單提交。提交數據時,用到了FormData對象來發送二進制文件,FormData構造函數提供的append()方法,除了直接添加二進制文件還能夠附帶一些其它的參數, 做爲XMLHttpRequest實例的參數提交給服務端。

使用jQuery提供的ajax方法來發送二進制文件,還須要附加兩個參數:

processData: false // 不要對data參數進行序列化處理,默認爲true
contentType: false // 不要設置Content-Type請求頭,由於文件數據是以 multipart/form-data 來編碼

Flash上傳

不少時候上傳的需求要求顯示上傳進度、中斷上傳過程、大文件分片上傳等等,這時傳統的表單上傳很難實現這些功能,因而產生了使用Flash上傳的方式,它採用Flash做爲一箇中間代理層,代替客戶端跟服務端通訊,此外,它也對客戶端的文件選擇方面擁有更多的控制權,比input[type=」file」] 要大得多。

在這裏我使用了jQuery封裝好的uploadify插件來進行演示,通常這類插件都自帶了上傳用的Flash文件,由於跟服務端回傳的數據和展現跟客戶端的交互,都是Flash文件的接口跟插件來對接的。

<div id="file_upload"></div>

 

html部分很簡單,預留一個hook後,插件會在這個節點內部建立Flash的object,而且還附帶建立了上傳進度、取消控件和多文件隊列展現等界面。

複製代碼
$(function() {
  $("#file_upload").uploadify({
      auto: true,
      method: "Post",
      width: 120,
      height: 30,
      swf: './uploadify.swf',
      uploader: 'http://uploadUrl',
      formData: {
          token: $("#token").val()
      },
      fileObjName: "file",
      onUploadSuccess: function(file, data, response){
          // 根據返回結果指定界面操做
      }
  });
});
複製代碼

 

關於jQuery.uploadify能夠訪問了解: http://www.uploadify.com/documentation/ 。值得注意的是flash並不適合手機端應用,更好的解決方案是使用flash+html5來解決平臺的兼容性問題。

截圖粘貼上傳

咱們發現如今有好多上傳應用已經提供了截圖粘貼上傳功能,如WebUploader,它就支持QQ截圖而後粘貼上傳。

首先,截圖粘貼上傳的核心思想是,監聽粘貼事件,而後獲取剪切板中的數據,若是是一張圖片,則觸發上傳事件。

代碼片斷以下:

複製代碼
$("textarea").on("paste", function(e){
   e.stopPropagation();
   var self = this;
   var clipboardData = e.originalEvent.clipboardData;
   if (clipboardData.items.length <= 0) {
       return;
   }
   var file = clipboardData.items[0].getAsFile();
   if (!file) {
       return;
   }
   var formData = new FormData();
   formData.append("file", file);
   formData.append("token", $("#token").val());
   $.ajax({
       url: "http://uploadUrl",
       type: "POST",
       data: formData,
   }).done(function(response) {
       // 根據返回結果指定界面操做
   });
   e.preventDefault();
});
複製代碼

 

從上面代碼能夠看出,上傳的過程都是同樣的,主要是獲取文件的方式。 當進行粘貼(右鍵paste/ctrl+v)操做時,觸發剪貼板事件’paste’,從系統剪切板獲取內容,而系統剪切板的數據在不一樣瀏覽器保存在不一樣的位置:

IE內核:windows.clipboardData
其它:e.originalEvent.clipboardData

拖拽上傳

拖拽上傳的方式,支持的瀏覽器比較少,由於它用到了HTML5的兩個新的屬性(API)一個是Drag and Drop,一個是File API

上傳域監聽拖拽的三個事件:dragEnterdragOverdrop,分別對應拖拽至、拖拽時和釋放三個操做的處理機制,固然你也能夠監聽dragLeave事件。

HTML5的File API提供了一個FileList的接口,它能夠經過拖拽事件的e.dataTransfer.files來傳遞的文件信息,獲取本地文件列表信息。

File API在HTML5規範中只是草案,在 W3C 草案中,File 對象只包含文件名、文件類型和文件大小等只讀屬性。但部分瀏覽器在草案以外提供了一個名爲 FileReader 的對象,用以讀取文件內容,而且能夠監控讀取狀態,它提供的方法有: 「readAsBinaryString」 ,」readAsDataURL」 ,」readAsText」 ,」abort」 等。

代碼片斷以下:

複製代碼
// dragenter
$("#textarea").on("dragenter", function(e){
    e.preventDefault();
});
// dragover
$("#textarea").on("dragover", function(e){
    e.preventDefault();
});
// drop
$("#textarea").on("drop", function(e){
    e.stopPropagation();
    e.preventDefault();
    var files = e.originalEvent.dataTransfer.files;
    _.each(files, function(file) {
        if (!/^image*/.test(file.type)) {
          return;
        }
        var fileReader = new FileReader();
        fileReader.onload = function() {
          //uploadFile(file);
        };
        fileReader.readAsDataURL(file);
    });
});
複製代碼

 

拖拽上傳過程當中的幾個關鍵點:

在drop事件觸發後經過e.dataTransfer.files獲取拖拽文件列表,在jQuery中是e.originalEvent.dataTransfer.files
拖拽上傳僅支持圖片,文件對象中file.type標識了文件類型。
因爲多是多圖拖拽,因此能夠遍歷圖片上傳,這裏用了Underscore的each方法。
這裏用readAsDataURL讀取文件內容爲二進制文件,你還能夠將其轉換爲Base64方式上傳,只是http協議裏面存在對非二進制數據的上傳大小限制爲2M。
上傳的過程跟前面的方式相同,即:建立FormData對象併發起Ajax請求。
拍照上傳

拍照上傳能夠是PC上的攝像頭拍照上傳也能夠是手機等移動設備的拍照上傳。手機上的拍照上傳最多見就是咱們使用微信發照片了。

手機實現拍照上傳的代碼:

<input type=file accept="image/*">
<input type=file accept="video/*">

ios 有拍照、錄像、選取本地圖片功能,部分android只有選取本地圖片功能。

上傳與安全

上傳文件時必須作好文件的安全性,除了前端必要的驗證,如文件類型、後綴、大小等驗證,重要的仍是要在後臺作安全策略。

這裏我列舉幾個注意點:

  • 後臺須要進行文件類型、大小、來源等驗證
  • 定義一個.htaccess文件,只容許訪問指定擴展名的文件。
  • 將上傳後的文件生成一個隨機的文件名,而且加上此前生成的文件擴展名。
  • 設置上傳目錄執行權限,避免不懷好意的人繞過如圖片擴展名進行惡意攻擊,拒絕腳本執行的可能性。
 
分類:  文件上傳
相關文章
相關標籤/搜索