express 如何上传文件的原理和实现

express 上传文件的原理和实现

  1. 原理
  2. formidable
  3. multer
  4. COS

1.原理

1.1 要想了解express上传 我们先看看 nodejs原生上传是怎么实现的

let server = require('http').Server(app);
server.listen(3000);

首先为了让express拥有原始http模块的一些功能

请不要使用 bodyParser 之类的中间件 因为不会next到这里 保持尽量原生。

app.post('/upload', async(req, res)=>{
  var postData =  '';
  req.on("data", function(postDataChunk) {  // 有新的数据包到达就执行
      postData += postDataChunk;

  });

  req.on("end", function() {  // 数据传输完毕
      console.log(postData);
      res.end('up success');

     // console.log('post data finish receiving: ' + postData );
  });

接下来前端模拟一个post请求 ajax form表单都行 假设我们传了个

<form action="/cos/upload"
      enctype="application/x-www-form-urlencoded"
      method="post">
    <p>
What is your name? <input type="text" name="name"><br>
<button class="btn-save" type="submit" >提交</button>
    </p>
</form>

在 post的 content-type="application/x-www-form-urlencoded" 下 后台console.log` 的 postData 应该是 name=xxx
这时候通过一些 querystring 之类的中间件解析出 key value数值 以方便我们操作
bodyParser这个中间件也是封装简化了流程 只要直接去req.body里面取就行。但有个弱点 对于file提交 就不能这么玩了! 那我们继续看看为什么

enctype="application/x-www-form-urlencoded" 改成 enctype= multipart/form-data另外增加个文件提交 再准备1个zip文件

<form action="/cos/upload"
      enctype="multipart/form-data"
      method="post">
    <p>
What is your name? <input type="text" name="name"><br>
What files are you sending? <input type="file" name="file" id="file"><br>
<button class="btn-save" type="submit" >提交</button>
    </p>
</form>

上传zip文件 和填写名称后 后台 console.logpostData 大概长这样

------WebKitFormBoundaryXKLAlaggDlZOVroE
Content-Disposition: form-data; name="name"

xxxx
------WebKitFormBoundaryXKLAlaggDlZOVroE
Content-Disposition: form-data; name="file"; filename="wrap.zip"
Content-Type: application/zip

PK?????bL?y??}??????wrap.jpgUT    ??]?Z??Zux?????????PS????HBKh?:   ??  ?zG"  一堆乱码

真的很吓人格式 其实除了乱码 还是有点规律 都通过WebKitFormBoundary 分割 还有一些头信息描述 和 文件内容 如果您想了解这些代表什么 请看 传送门

让我们改进下代码 取消掉name字段 end 里生成文件

req.on("end", function() {  // 数据传输完毕

       fs.writeFile('./upload/sss.zip',postData,'binary',function(err){  //path为本地路径例如public/logo.png
           if(err){
             console.log('保存出错!')
               res.end('up failed');

           }else{
               console.log('保存成功!')
               res.end('up success');
           }
       })

      // console.log('post data finish receiving: ' + postData );
   });

这段代码的目的是 接受前端的zip包 然后保存为服务器端的upload文件下sss.zip。 很显然 运行是成功了 也生成了 但双击解压时候就愣逼了 无法打开。 看了下2个zip的大小 很明显已经发送了变化 。原因就出在一些其他的东西也进入了数据体(就是刚才乱码部分) 如果name没取消 那么信息将会更混乱 怎么解决呢?其实也很简单 只是少了个解析中间件 当然也有大神手写 根据一定规则 split啊 正则啊

2.formidable

formidable 就是一款解析软件 npm install 下 和 var formidable = require(‘formidable‘)

app.post('/upload', async(req, res)=>{

    var form = new formidable.IncomingForm();
    form.uploadDir = "./upload";
    //form.keepExtensions = true; 是否保持上传什么后缀 保存什么后缀 默认没有后缀

    form.parse(req, function(err, fields, files) {
            res.writeHead(200, {'content-type': 'text/plain'});
            res.write('received upload:\n\n');

            var tmpPath=files.file.path; //临时保存路径
            var fileName=files.file.name;
            fs.rename(tmpPath,path.resolve(form.uploadDir,fileName),function (err) {

                if(err){
                    console.log('保存出错!')
                }
                else{
                    console.log('保存成功!')
                }
                res.end();
            })
        });

然后打开生成的zip文件。这次能正常解压 说明数据没发生破坏。 formidable 也有很多 事件驱动api 如 progress error 等 具体看文档

这里我原名保存了上传文件 按实际情况定义。

3.Multer

multer 就是一款express官方推荐的上传中间件 。和formidable 差不多 但是官方送的最基础的上传 如果你想扩展功能 如上传进度条,断点续传 阿里oss 腾讯cos 等内容仓库 还要你自己想办法 融进去。github上已经有部分写好的 可以去看看 这里给出我的配置 可以参考参考

let setMulter = require('../util/myMulter');

//文件上传服务
router.post('/upload',  function (req, res, next)  {

  //这是自己写的一个封装势力 为了想以后扩展
  var upload=setMulter('file',1);

  upload(req, res, function (err) {

         try {
              if (err) throw err;
              if(req.files.length==0) throw new  Error("不能上传空文件"); //官方没有空文件的办法 再这里添加

             res.send('文件上传成功');

         }
         catch (err) {
                 console.log(err.message);
                 res.send(`文件上传失败,原因:${err.message}`);
         }
   });
});

** myMulter.js **

let path=require('path');
let multer = require('multer');
//api https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md

let dir=path.resolve(__dirname,'../upload');

const mimes = {
    '.png': 'image/png',
    '.gif': 'image/gif',
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.zip':'application/zip'
};

//定义仓库
const storage = multer.diskStorage({

    //Note:如果你传递的是一个函数,你负责创建文件夹,如果你传递的是一个字符串,multer会自动创建
    destination: function (req, file, cb) {
        cb(null, dir);
    },
    //获取文件MD5,重命名,添加后缀,文件重复会直接覆盖
    filename: function (req, file, cb) {

        var ext =(file.originalname).split('.').pop();
        cb(null, `${file.fieldname}-${Date.now()}.${ext}`);
    }
});

//定义过滤器
const fileFilter =function  (req, file, cb) {

    // 指示是否应接受该文件
    var test = Object.values(mimes).filter(function(type) {
        return type===file.mimetype;
    })

    // 接受这个文件,使用`true`,像这样:
    if(test){
        cb(null, true);
    }else{ // 拒绝这个文件,使用`false`,像这样:

        cb(new Error('file mimes not allow!'), false);
    }

}

//定义限制
const limits={
    fileSize:1024 * 1024 * 30
};

module.exports=function(opt) {

    return  multer({
        storage: storage,
        fileFilter:fileFilter,
        limits: limits,
    }).array(opt);
};

如果你想添加进度条 请参考 这个

4.COS

目前再研究中。。。

原文地址:https://www.cnblogs.com/lanbosm/p/8531862.html

时间: 2024-10-27 19:08:40

express 如何上传文件的原理和实现的相关文章

Web上传文件的原理及实现

现在有很多Web程序都有上传功能,实现上传功能的组件或框架也很多,如基于java的Commons FileUpload.还有Struts1.x和Struts2中带的上传文件功能(实际上,Struts2在底层也使用了Commons FileUpload). 虽然现在有很多上传组件可以利用,但是了解Web上传文件的原理,对于处理突然出现的问题会有很大的帮助,下面就来讲一下通过浏览器上传文件的基本原理.在了解了原理之后,就可以非常容易地自制满足自身需要的上传组件了. 众所周知,在客户端代码中需要使用<

[转]文件上传原理:Web上传文件的原理及实现

现在有很多Web程序都有上传功能,实现上传功能的组件或框架也很多,如基于java的CommonsFileUpload.还有Struts1.x和Struts2中带的上传文件功能(实际上,Struts2在底层也使用了CommonsFileUpload).在asp.net中也有相应的上传文件的控件. 虽然现在有很多上传组件可以利用,但是了解Web上传文件的原理,对于处理突然出现的问题会有很大的帮助,下面就来讲一下通过浏览器上传文件的基本原理.在了解了原理之后,就可以非常容易地自制满足自身需要的上传组件

Nodejs学习笔记(八)--- Node.js + Express 实现上传文件功能(felixge/node-formidable)

目录 前言 formidable简介 创建项目并安装formidable 实现上传功能 运行结果 部分疑惑解析 写在之后 前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能----文件上传,示例以一个上传图片的功能为例子 上传功能命名用formidable实现,示例很简单! PS:最近比较忙,距上一次更新已经比较久了^_^! formidable简介 nodejs原生实现上传还是比较麻烦,有兴趣的自已去参考一下网上有网友写的代码 这里选择了formidable,也是githu

ajax上传文件的原理与实现

    ajax已经很普遍了,但使用 ajax上传文件自己却一直都没有涉及,我只知道挺复杂的,上传文件不同于上传一般的表单数据,必须特殊处理,知道一般ajax使用上传都是应用一个虚拟的iframe,但由于项目需要,在网上找了找,没想到找到了两个支持ajax上传文件的jquery插件,jquery.uploadify.js和dropzone.min.js两个都可以实现ajax上传文件,效果也不错. 1使用jquery.uploadify.js上传文件  这种上传方式,使用了Flash,因此需要引用

nodejs express 框架 上传文件

web 项目应用express4.0框架 html 表单post 文件上传失败,后端无法获取提交文件 express不支持文件上传. 方式一 若是图片,可以将图片转码为BASE64上传 前端框架angularjs代码 转换代码如下 $scope.filechange=function(index){ var file = this.files[0]; var url = webkitURL.createObjectURL(file); /* 生成图片 * --------------------

隐藏iframe无刷新上传文件

首先ajax不能上传文件,这误导了我有段时间,今晚睡不着就照着说明做了个无刷新上传文件 其实原理很简单 <form enctype="multipart/form-data" method="POST" target="upload" action="http://localhost/class.upload.php" > <input type="file" name="upl

Node Express 上传文件

1, 安装上传文件依赖 multer => npm i multer -D 2, 基本使用 // 引入必要文件 let express = require('express'); let multer = require('multer'); let fs = require('fs'); let path = require('path'); // 初始化服务器 let app = express(); app.listen(80); // 配置接收的文件在服务器的临时存放路径, any()

atitit.ajax上传文件的实现原理 与设计

atitit.ajax上传文件的实现原理 与设计 1. 上传文件的三大难题 1 1.1. 本地预览 1 1.2. 无刷新 1 1.3. 进度显示 1 2.  传统的html4  + ajax 是无法直接实现上传文件 1 2.1. 传统的实现方式iframe 2 2.2. html5转码base64 3 2.3. 其它插件FLASH的实现原理 3 3. 上传进度的实现原理 3 3.1. 使用ajax结合服务端的进度返回,比較麻烦 4 4. 本地预览的解决 4 4.1. 用HTML5上传文件 4 5

node.js express fs 获取已上传文件数据格式

{ "fieldName": "photo", "originalFilename": "1395130808991.jpg", "path": "tmpupload/25546-z8u01y.jpg", "headers": { "content-disposition": "form-data; name=\"photo\&