0

0

Nodejs+express中间件实现文件上传

青灯夜游

青灯夜游

发布时间:2021-04-16 11:00:49

|

2491人浏览过

|

来源于掘金社区

转载

本篇文章给大家详细介绍nodejs文件上传的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

Nodejs+express中间件实现文件上传

笔者用nodejs做项目时需要用到文件上传的功能,在网上搜索了很多教程,找到了一个express的中间件,用于处理multipart/form-data类型的表单数据,可以很方便的将表单中的文件数据保存到服务器。

介绍


multer是一个node.js文件上传中间件,它是在 busboy的基础上开发的,上传的表单数据必须是multipart/form-data类型,不然会报错。【相关推荐:《nodejs 教程》】   

简单的用法


定义存储器

Multer作为express的一个中间件,我们可以很方便的自定义上传的文件目录以及保存的文件名。先看一个最简单的用法,demo1地址

var express = require('express');
var multer = require('multer');
var app = express();

var upload = multer({
    storage: multer.diskStorage({
        destination: function (req, file, cb) {
            cb(null, './uploads/');
        },
        filename: function (req, file, cb) {
            //file.originalname上传文件的原始文件名
            var changedName = (new Date().getTime())+'-'+file.originalname;
            cb(null, changedName);
        }
    })
});

我们先创建了一个upload对象,这个对象中destination函数用来定义上传文件的存储的文件夹;filename函数用来修改上传文件存储到服务器的文件名称,这里我们我们加上一个时间戳简单区分一下。这两个函数都是通过回调函数来实现的。每次上传的时候这两个函数都会调用一次,如果是多个文件上传,那个这两个函数就调用多次,调用顺序是先调用destination,然后调用filename。

在两个函数中都会有一个file对象,表示当前上传的文件对象,有以下几个属性:

  • fieldname:上传的字段名
  • originalname:上传的文件名
  • encoding:文件的编码类型
  • mimetype:文件的MIME类型

附:一些常用的MIME类型

定义路由回调

//单个文件上传
app.post('/upload/single',upload.single('singleFile'),(req,res)=>{
    console.log(req.file);
    res.json({
        code: '0000',
        type:'single',
        originalname: req.file.originalname
    })
});

//多个文件上传
app.post('/upload/multer',upload.array('multerFile'),(req,res)=>{
    console.log(req.files);
    let fileList = [];
    req.files.map((elem)=>{
        fileList.push({
            originalname: elem.originalname
        })
    });
    res.json({
        code: '0000',
        type:'multer',
        fileList:fileList
    });
});

在express中定义路由的回调函数时,把定义好了的upload对象作为中间件添加进去。如果是单个文件就用single方法,如果是多个文件就用array方法,这两个方法都需要传一个页面上定义好的字段名。

在路由的回调函数中,request对象已经有了file属性(单个文件上传)或files属性(多个文件上传),files属性是一个数组,数组的每一个对象都有以下属性:

  • fieldname:上传的字段名
  • originalname:上传的文件名
  • encoding:文件的编码类型
  • mimetype:文件的MIME类型
  • destination:存储的目录(和destination回调函数中的目录名一致)
  • filename:保存的文件名(和filename回调函数中的文件名一致)
  • path:保存的相对路径
  • size:文件的大小(单位:字节byte)

  我们可以发现在路由的回调函数中的file对象比diskStorage中的file对象多了几个属性,这是因为在diskStorage中文件还没有保存,只能知道文件的大致属性;而路由的回调函数文件已经在服务器上保存好了,文件的保存路径以及文件的大小都是已知的。

混合上传

I-Shop购物系统
I-Shop购物系统

部分功能简介:商品收藏夹功能热门商品最新商品分级价格功能自选风格打印结算页面内部短信箱商品评论增加上一商品,下一商品功能增强商家提示功能友情链接用户在线统计用户来访统计用户来访信息用户积分功能广告设置用户组分类邮件系统后台实现更新用户数据系统图片设置模板管理CSS风格管理申诉内容过滤功能用户注册过滤特征字符IP库管理及来访限制及管理压缩,恢复,备份数据库功能上传文件管理商品类别管理商品添加/修改/

下载

有时候我们可能需要用字段名来对上传的文件进行一下划分,比如说上传多个图片的时候可能有身份证还有头像。虽然可以分开放到两个接口中,但是会产生其他一系列的麻烦事。multer支持对图片进行字段名的划分。demo3地址

//多字段名上传
let multipleFields = upload.fields([
    {name:'avatar'},
    {name:'gallery', maxCount:3},
]);
app.post('/upload/fields', (req,res)=>{
    multipleFields(req,res,(err) => {
        console.log(req.files);
        if(!!err){
            console.log(err.message);
            res.json({
                code: '2000',
                type: 'field',
                msg:err.message
            })
            return;
        }
        var fileList = [];
        for(let item in req.files){
            var fieldItem = req.files[item];
            fieldItem.map((elem) => {
                fileList.push({
                    fieldname: elem.fieldname,
                    originalname: elem.originalname
                })
            });
        }
        res.json({
            code: '0000',
            type: 'field',
            fileList: fileList,
            msg:''
        })
    });
});

在这边也有req.files属性,但是这个属性并不是一个数组,而是一个复杂的对象,这个对象中有多个属性,每个属性名都是一个字段名,每个属性下面又是一个数组,数组下面才是一个个的文件对象,结构大致如下:

{
    "avatar":[{
        fieldname: "",
        originalname: ""
        //...
    }],
    "gallery":[{
        fieldname: "",
        originalname: ""
        //...
    }]
}

过滤文件上传


在文件上传时,有时候会上传一些我们不需要的文件类型,我们需要把一些不需要的文件给过滤掉。demo2地址

文件类型过滤

var upload = multer({
    //...其他代码
    fileFilter: function(req, file, cb){
        if(file.mimetype == 'image/png'){
            cb(null, true)
        } else {
            cb(null, false)
        }
    }
});

  在定义存储器的时候,新增一个fileFilter函数,用来过滤掉我们不需要的文件,在回调函数中我们传入true/false来代表是否要保存;如果传了false,那么destination函数和filename函数也不会调用了。

文件大小和数量过滤

var upload = multer({
    //...其他代码
    limits:{
        //限制文件大小10kb
        fileSize: 10*1000,
        //限制文件数量
        files: 5
    }
});

在定义存储器的时候,新增一个limits对象,用来控制上传的一些信息,它有以下一些属性:

  • fieldNameSize:field 名字最大长度,默认值:100 bytes
  • fieldSize:field 值的最大长度,默认值:1MB
  • fields:非文件 field 的最大数量
  • fileSize:在multipart表单中, 文件最大长度 (字节单位)
  • files:在multipart表单中, 文件最大数量
  • parts:在multipart表单中, part传输的最大数量(fields + files)

在这边我们把fileSize的值设置得小一点,设为10kb方便测试看效果,但是如果这个时候会发现有报错。因为上传的文件大小很容易就会超过10KB,导致有报错出现,我们就需要在路由回调里对错误的情况进行捕获。

//单个文件上传
let singleUpload = upload.single('singleFile');
app.post('/upload/single',(req,res)=>{
    singleUpload(req,res,(err)=>{
        if(!!err){
            console.log(err.message)
            res.json({
                code: '2000',
                type:'single',
                originalname: '',
                msg: err.message
            })
            return;
        }
        if(!!req.file){
            res.json({
                code: '0000',
                type:'single',
                originalname: req.file.originalname,
                msg: ''
            })
        } else {
            res.json({
                code: '1000',
                type:'single',
                originalname: '',
                msg: ''
            })
        }
    });
});

//多个文件上传
let multerUpload = upload.array('multerFile');
app.post('/upload/multer', (req,res)=>{
    multerUpload(req,res,(err)=>{
        if(!!err){
            res.json({
                code: '2000',
                type:'multer',
                fileList:[],
                msg: err.message
            });
        }
        let fileList = [];
        req.files.map((elem)=>{
            fileList.push({
                originalname: elem.originalname
            })
        });
        res.json({
            code: '0000',
            type:'multer',
            fileList:fileList,
            msg:''
        });
    });
});

所有的demo代码都在仓库里,地址:https://github.com/acexyf/multerDemo

更多编程相关知识,请访问:编程入门!!

相关专题

更多
node.js调试
node.js调试

node.js调试可以使用console.log()输出调试信息、断点调试和第三方调试工具。详细介绍:1、console.log()输出调试信息,通过在代码中插入console.log()语句,开发人员可以在控制台输出变量的值、函数的执行结果等信息,以便观察代码的执行流程和状态;2、断点调试,可以在代码中设置断点,以便在特定位置暂停代码的执行,观察变量的值和执行流程等。

342

2023.09.19

JavaScript 全栈开发基础(Node.js + 前端)
JavaScript 全栈开发基础(Node.js + 前端)

本专题系统介绍 JavaScript 在全栈开发中的核心知识结构,涵盖 Node.js 基础、Express/Koa 接口构建、前端交互设计、模块化与包管理、数据库连接、前后端数据通信与部署流程。通过完整项目示例,帮助学习者掌握从浏览器到服务器的一体化开发能力,实现真正意义上的全栈入门。

88

2025.11.26

什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

175

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

212

2025.12.18

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

989

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

50

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

208

2025.12.29

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

508

2023.06.20

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
快速入门Node.JS全套完整版
快速入门Node.JS全套完整版

共83课时 | 8.1万人学习

nodejs开发基础教程
nodejs开发基础教程

共15课时 | 4.5万人学习

JavaScript设计模式视频教程
JavaScript设计模式视频教程

共28课时 | 5.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号