利用Ajax無刷新上傳文件到Node.js服務器
最近做一個垂直社區項目,圖片上傳是現如今社區的標配,何況面向的還是女性用戶。后端使用Node.js,圖片上傳必然是要不刷新不用iframe了。順便,也測試了一下Coding.net的“演示”功能,的確是方便免費夠用,代碼傳上去基本零配置就可以跑起來了。這篇文章涉及的代碼托管在Coding上,最終的例子也是運行在Coding的免費服務器上。
協議與結構
整個上傳采用RFC1867協議,即基于HTML表單的文件上傳協議。借助這個協議,為表單增加enctype="multipart/form-data",再使用type為file的input控制來選擇文件,然后便可用POST方法上傳文件。
文件上傳時會分段提交,借助Connect的connect-multiparty模塊,即可接收各段組合整理為文件,并將文件存到臨時目錄,我們可再編寫其它代碼來處理文件。本例中,我們會把文件復制到public目錄,以提供web訪問。
整個示例程序包括以下幾部分:
- HTML表單,負責文件的選擇
- JavaScript組織表單數據,執行上傳
- Node.js接受上傳的文件,并負責文件的移動和組織
示例程序的代碼托管在Coding上的Node.js-Ajax-Upload-File,在線演示地址為node-js-ajax-upload-file.codingapp.com。
下面開工。
HTML表單組織
表單很簡單,就一個文件選擇的控件。當type為file的input控件除了常規屬性,還包括一個accept屬性,用于定義可以選擇的文件類型。
HTML中包括一個表單,一個提交按鈕,和一個顯示成功上傳到服務器的圖片的控件,主要代碼如下:
<form class = "form-horizontal" enctype='multipart/form-data' method='post' action='javascript:;' role = "form" id = "frmUploadFile"> <div class = "form-group"> <label class = "control-label col-sm-2">上傳選擇</label> <div class = "col-sm-4"> <input type = "file" name = "files" class = "form-control" /> </div> </div> <div class = "form-group"> <div class = "col-sm-offset-2 col-sm-4"> <button class = "btn btn-primary" onClick = "uploadFile()">上傳</button> <span class = "help-inline" id = "spanMessage">選擇文件,并上傳</span> </div> </div> </form> <div class = "row" style = "text-align: center"> <img id = "imgShow" /> </div>
完整代碼請查看public/index.html。
Ajax執行上傳
瀏覽器端的JavaScript會將表單中的數據格式化,再以POST方法上傳文件,為了簡便,使用了jQuery庫來操作,具體代碼比較簡單,上傳文件,然后根據服務器端的返回判定上傳是否成功,如果成功,則顯示圖片。
代碼包裝為自定義的函數,由“發送”按鈕的單擊事件調用,代碼如下:
function uploadFile(){ var formData = new FormData($("#frmUploadFile")[0]); $.ajax({ url: '/upload', type: 'POST', data: formData, async: false, cache: false, contentType: false, processData: false, success: function(data){ if(200 === data.code) { $("#imgShow").attr('src', data.msg.url); $("#spanMessage").html("上傳成功"); } else { $("#spanMessage").html("上傳失敗"); } console.log('imgUploader upload success, data:', data); }, error: function(){ $("#spanMessage").html("與服務器通信發生錯誤"); } }); }
具體請參見文件pubilc/demo.js。
Node.js接收文件
通過POST接收到的文件,由connect-multiparty負責重新組織為文件,并存儲到臨時文件夾中,Linux默認為/tmp目錄,然后再將文件信息放到req.files對象中,對象中按input的name屬性來組織文件列表,我們上面的表單中的input控件name為files,所以文件的信息便存儲在req.files.files中。通過它可獲取文件的存儲位置和文件名等信息。
整個服務器端的代碼很簡單,連同注釋不過20多行,其中處理請求部分的代碼如下:
var multipart = require('connect-multiparty'); app.post('/upload', multipart(), function(req, res){ //get filename var filename = req.files.files.originalFilename || path.basename(req.files.files.ws.path); //copy file to a public directory var targetPath = path.dirname(__filename) + '/public/' + filename; //copy file fs.createReadStream(req.files.files.ws.path).pipe(fs.createWriteStream(targetPath)); //return file url res.json({code: 200, msg: {url: 'http://' + req.headers.host + '/' + filename}}); });
完整代碼請參閱app.js。
示例程序的運行
如果系統中已經安裝了git,則可以用下面的命令克隆:
|
|
也可以下載zip包,程序中的前端包都使用的是百度的公開庫,后端代碼使用npm管理,進入應用目錄,執行如下的命令安裝:
|
|
然后執行如下的命令可以啟動應用:
|
|
再通過瀏覽器訪問http://ip:3000/即可。注意,上傳的文件會保存在/tmp和public兩個目錄中。
來自:http://chensd.com/2015-01/Node-js-Ajax-Upload-File.html