1. 程式人生 > >Nodejs學習筆記(八)—Node.js + Express 實現上傳文件功能(felixge/node-formidable)

Nodejs學習筆記(八)—Node.js + Express 實現上傳文件功能(felixge/node-formidable)

blog args 一個 type屬性 ole java mod device 前端

前言

  前面講了一個構建網站的示例,這次在此基礎上再說說web的常規功能----文件上傳,示例以一個上傳圖片的功能為例子

  上傳功能命名用formidable實現,示例很簡單!

  PS:最近比較忙,距上一次更新已經比較久了^_^!

formidable簡介

  nodejs原生實現上傳還是比較麻煩,有興趣的自已去參考一下網上有網友寫的代碼

  這裏選擇了formidable,也是github上同類功能模塊人氣比較高的

  https://github.com/felixge/node-formidable

  https://www.npmjs.org/package/formidable

  優點:上傳速度比較可觀,占用內存也比較低,簡單易用...

創建項目安裝formidable

  1.創建項目sampleUpload

cd 工作目錄

express -e sampleUpload

  2.修改package.json文件,添加formidable依賴項

{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "express": "~4.0.0",
    "static-favicon": "~1.0.0",
    "morgan": "~1.0.0",
    "cookie-parser": "~1.0.1",
    "body-parser": "~1.0.0",
    "debug": "~0.7.4",
    "ejs": "~0.8.5",
    "formidable" : "latest"
  }
}

  3.安裝依賴項

cd sampleUpload && npm install

  安裝成功,一切準備就緒,開始完成這個功能!

實現上傳功能

  1.index.ejs文件中構建表單並實現前端驗證(樣式使用和https://www.cnblogs.com/flyingeagle/p/9192962.html一致)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">       
    <title><%= title %></title>
  
      <link rel="stylesheet" type="text/css" href="/stylesheets/bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" href="/stylesheets/signin.css" />
  </head>

  <body>

    <div id="container" class="container">
       <% if (locals.success) { %> 
          <div id="alt_sucess" class="alert alert-success"> 
            <%- success %> 
          </div> 
       <% } %> 

      <% if (locals.error) { %> 
        <div id="alt_warning" class="alert alert-warning"> 
          <%= error %> 
        </div> 
      <% } %> 

      <form class="form-signin" role="form" method="post" enctype=‘multipart/form-data‘>
        <h2 class="form-signin-heading">上傳文件</h2>
        <input id="fulAvatar" name="fulAvatar" type="file" class="form-control" />     
        <br/>
        <button id="btnSub" class="btn btn-lg btn-primary" type="submit">上 傳</button>
      </form>
            
    </div> 
  </body>
</html>

<script src="/javascripts/jquery-1.11.1.min.js" type="text/javascript"></script>

<script type="text/javascript">
     String.prototype.format = function (args) {
            var result = this;
            if (arguments.length > 0) {
                if (arguments.length == 1 && typeof (args) == "object") {
                    for (var key in args) {
                        if (args[key] != undefined) {
                            var reg = new RegExp("({" + key + "})", "g");
                            result = result.replace(reg, args[key]);
                        }
                    }
                }
                else {
                    for (var i = 0; i < arguments.length; i++) {
                        if (arguments[i] != undefined) {
                            var reg = new RegExp("({)" + i + "(})", "g");
                            result = result.replace(reg, arguments[i]);
                        }
                    }
                }
            }
            return result;
    }

    $(function(){
        $(‘#btnSub‘).on(‘click‘,function(){           
            var fulAvatarVal = $(‘#fulAvatar‘).val(),  
                errorTip = ‘<div id="errorTip" class="alert alert-warning">{0}</div> ‘;  

            $("#errorTip,#alt_warning").remove();
            
            if(fulAvatarVal.length == 0)
            {
                $("#container").prepend(errorTip.format(‘請選擇要上傳的文件‘));                                
                return false;
            }

           var extName = fulAvatarVal.substring(fulAvatarVal.lastIndexOf(‘.‘),fulAvatarVal.length).toLowerCase();

            if(extName != ‘.png‘ && extName != ‘.jpg‘){
               $("#container").prepend(errorTip.format(‘只支持png和jpg格式圖片‘));                             
               return false;                
            }
            
            return true;                
        })
    });

</script>

  這裏一定要註意表單的enctype屬性,這個就不多作解釋了,如果是初次接觸,看看http://www.w3school.com.cn/tags/att_form_enctype.asp

  2.實現index.js中上傳邏輯

var express = require(‘express‘)
    router = express.Router(),    
    formidable = require(‘formidable‘),
      fs = require(‘fs‘),
      TITLE = ‘formidable上傳示例‘,
    AVATAR_UPLOAD_FOLDER = ‘/avatar/‘

/* GET home page. */
router.get(‘/‘, function(req, res) {
  res.render(‘index‘, { title: TITLE });
});

router.post(‘/‘, function(req, res) {

  var form = new formidable.IncomingForm();   //創建上傳表單
      form.encoding = ‘utf-8‘;        //設置編輯
      form.uploadDir = ‘public‘ + AVATAR_UPLOAD_FOLDER;     //設置上傳目錄
      form.keepExtensions = true;     //保留後綴
      form.maxFieldsSize = 2 * 1024 * 1024;   //文件大小

    form.parse(req, function(err, fields, files) {

        if (err) {
          res.locals.error = err;
          res.render(‘index‘, { title: TITLE });
          return;        
        }  
       
        var extName = ‘‘;  //後綴名
        switch (files.fulAvatar.type) {
            case ‘image/pjpeg‘:
                extName = ‘jpg‘;
                break;
            case ‘image/jpeg‘:
                extName = ‘jpg‘;
                break;         
            case ‘image/png‘:
                extName = ‘png‘;
                break;
            case ‘image/x-png‘:
                extName = ‘png‘;
                break;         
        }

        if(extName.length == 0){
              res.locals.error = ‘只支持png和jpg格式圖片‘;
              res.render(‘index‘, { title: TITLE });
              return;                   
        }

        var avatarName = Math.random() + ‘.‘ + extName;
        var newPath = form.uploadDir + avatarName;

        console.log(newPath);
        fs.renameSync(files.fulAvatar.path, newPath);  //重命名
    });

    res.locals.success = ‘上傳成功‘;
    res.render(‘index‘, { title: TITLE });      
});

module.exports = router;

  註意:在public文件夾中創建avatar文件夾以供文件存放

運行結果

  1.在app.js中添加8000端口的監聽

  2.cd到項目根目錄,運行node app

  3.瀏覽器上訪問 localhost:8000

  技術分享圖片

  4.上傳圖片

  技術分享圖片
  5.去上傳文件夾中查看

  技術分享圖片

  大功告成!

部分疑惑解析

  有一些在代碼中有註釋的我就不解釋了

  1.怎麽沒看到上傳?

  註意:form.parse 再看看formidable的解釋

Automatically writing file uploads to disk

  2.為什麽需要fs.renameSync

  原因和上一個問題有關,它會自動被上傳到用戶的臨時目錄(這個可以把files.fulAvatar.path輸出來看一下便知) http://nodejs.org/docs/latest/api/fs.html#fs_fs_renamesync_oldpath_newpath

  3.可不可以看到上傳進度

  可以,https://github.com/felixge/node-formidable#events (仔細看看events,可能有你要用的其它部分)

  但是只是在控制臺輸出,想在前端去顯示進度條是不行的(沒有去研究,想想別的辦法應該也可以)

  4.文件名想命名UUID不重復,在nodejs中怎麽辦?

  可以使用node-uuid,調用簡單 https://github.com/broofa/node-uuid

  ...

  其它的留言問吧^_^!

寫在之後

  功能比較簡單,代碼也是示例風格,大家主要關註一下使用

  代碼結構優化方向:

  1.比如文件後綴這一類的方法可以放到一個pub.js中,此js專門用於這些公有方法

  2.可以利於返回值的方式去返回數據,前端根據返回值做出相應的提示

  3.可以利於jquery.form.js去提交表單,post中用res.json方法返回值,優化體驗(同樣引用這個js也會增大頁面體積)

  ....

  總之是個小例子,大家將就著看看吧^_^!

文章來源:https://www.cnblogs.com/zhongweiv/p/nodejs_express_formidable.html

Nodejs學習筆記(八)—Node.js + Express 實現上傳文件功能(felixge/node-formidable)