Nodejs對檔案上傳的處理
在Express4裡req.files已經是undefined了;現在用的最多的可能就是formidable了,你知道了它有個progress事件,於是心中大喜,低版本IE的進度條有戲了;OK,試試看:
form .on('error',function(err){ console.log(err); }) .on('aborted',function(){ console.log('aborted'); }) .on('progress',function(bytesReceived, bytesExpected){ var n=parseInt(parseFloat(bytesReceived/bytesExpected).toFixed(2)*100); console.log(n); });
是的,你很高興的看到了,控制台按照預期打印了一串進度值;那麼,再進一步;
form .on('progress',function(bytesReceived, bytesExpected){ var n=parseInt(parseFloat(bytesReceived/bytesExpected).toFixed(2)*100); res.write('<script>window.parent.call('+n+')</script>'); //无刷新上传,你们懂的 console.log(n); });
all在頁面上顯示進度值;很不幸,你只能看到最後的100%,看不到上傳具體詳細的進度值;再探...接下來換個思路,試一下,將進度值保存到session裡,額外加一個請求來輪詢這個進度值,哎喲,好!為了確保你請求的進度值是你這次上傳的進度值而不是其他上傳的進度值,需要在上傳的請求里和額外的請求裡約定一個token值;現在又來一個問題就是怎麼在請求的時候得到這個token,由於檔案上傳的請求體在Request Payload裡,所以req.body拿不到帶過去的值,我也不想去解析這堆了,當然我也解析不了;放在url裡最好,問題在於有時候得刷新兩次來刷新token,不好!不得已,我還是放在cookie裡吧!
var cookies=function () { var cks=req.headers.cookie.split(';'),obj={}; for(var i=0;i<cks.length;i++){ obj[cks[i].split('=')[0].replace(/\s+/ig,'')]=unescape(cks[i].split('=')[1]); } return obj; }(); var queryToken=cookies.__token__; form .on('progress',function(bytesReceived, bytesExpected){ var n=parseInt(parseFloat(form.bytesReceived/form.bytesExpected).toFixed(2)*100); if (req.session['file'+queryToken]) { req.session['file'+queryToken].percent=n; }else{ req.session['file'+queryToken]={ token:queryToken, percent:n } }; console.log(n); });
var getData=function(){ $.post('/uploader',{ getfileinfo:1, uploadtoken:utils.cookie.getCookie('__token__') }) .then(function(data){ console.log(data); if (data.mes<0) { getData(); }else{ var pros=data.info; call(pros.percent); if (pros.percent!='100') { getData(); }; }; }); } getData();
能看到最後的100%,看不到上傳具體詳細的進度值;再探...
好吧,我又一次淪陷了;不過還是感覺不對勁,ajax輪詢沒有問題,問題在於session裡要等到上傳完畢才有值,所以只能看到100%,看不到詳細進度值;我是否可以認為,在progress裡,之前的res.write和這次的req.session被掛起了呢,但是它又保存了每次的執行結果,直到progress完再釋放,所以只能看到100%;沒心情看formidable的源碼,當然我也看不咋懂,我就先這麼認為吧!
既然ajax輪詢沒問題,那麼就是保存到session不得勁了;實在不成,放到global裡試試吧,總不會往全域物件裡塞個值也會掛起吧;稍作改動放到global裡:
form .on('progress',function(bytesReceived, bytesExpected){ var n=parseInt(parseFloat(form.bytesReceived/form.bytesExpected).toFixed(2)*100); if (global['file'+queryToken]) { global['file'+queryToken].percent=n; }else{ global['file'+queryToken]={ token:queryToken, percent:n } }; console.log(n); });
繼續輪詢。
漂亮,完全就是那麼回事!在chrome裡看到的和HTML5的進度一個效果,只是在IE789裡會有點卡頓的感覺,不過還是能看到詳細的進度值的;畢竟老瀏覽器身子骨不咋地,你們懂的;還有,每次上傳都往global裡塞值,怎麼也得適當的清理一下吧,檔案上傳完畢,轉移到指定目錄後global['file'+queryToken]=null;
然而,輪詢,就是一個接一個好多好多的請求,這裡也許會出問題;要不限制一下吧,間隔500ms請求一次進度值;恩,IE789進度條就這麼解決了,說好的丟掉flash;雖然這個輪詢可以兼容所有瀏覽器,但畢竟要浪費那麼多請求,還是判斷下,在IE789以外繼續HTML5吧!
其實衡量一下,額外加個flash上傳和額外的請求,哪個更值呢,原諒我不懂flash,就不多說了,反正我很不喜歡在頁面上加一下額外的文件;
總結
關於文件上傳的元件,還有很多的細節處理,本想弄一個JS文件的,後來一想,為了可復用性更強,還是作為一個獨立的頁面搞比較好,需要上傳的地方, iframe一下就行了,一定比弄一個JS檔好很多。以上就是這篇文章的全部內容,希望能夠對大家的學習或工作帶來一定的幫助,如果有疑問大家可以留言交流。
更多Node.js實作相容IE789的檔案上傳進度條相關文章請關注PHP中文網!