最终实现的效果,更改Input的值后,将图片显示出来、输入描述信息,提交后,图片上传到后台对应的路径下。
Multer 实现本地文件/图片上传

Multer

  • Multer 是一个node.js中间件,用于处理 multipart/form-data类型的表单数据,主要用于上传文件。
  • 在form表单上要加上 enctype=“multipart/form-data” 的属性。
  • Multer 不会处理任何非 multipart/form-data 类型的表单数据。
  • 不要将 Multer 作为全局中间件使用,因为恶意用户可以上传文件到一个你没有预料到的路由,应该只在你需要处理上传文件的路由上使用。

1. 安装

终端中输入以下命令
npm install --save multer
或者使用yarn命令
yarn add multer -S

2. 简单使用

const express=require("express");
const multer=require("multer");
const app=express();

app.post("/upload",uploadFile,(req,res)=>{
    //这里的req.body是经过uploadFile中间件进行处理后的,包含了表单中所有的提交内容
    console.log(req.body);
    res.send("文件上传成功");
})

//自定义中间件
function uploadFile(req,res,next){
	//dest 值为文件存储的路径;single方法,表示上传单个文件,参数为表单数据对应的key
	let upload=multer({dest:"attachment/"}).single("photo");
	upload(req,res,(err)=>{
		//打印结果看下面的截图
	    console.log(req.file);
		if(err){
	        res.send("err:"+err);
	    }else{
	        //将文件信息赋值到req.body中,继续执行下一步
	        req.body.photo=req.file.filename;
	        next();
	    }
	})
}
app.listen(3000);

表单提交文件,访问 localhost:3000/upload 接口后,就可以在attachment 目录里看到刚刚上传的文件,为了避免命名冲突,Multer 默认会修改上传的文件名为随机字符。如果想自定义文件名称, 可以在 DiskStorage 中配置。
Multer 实现本地文件/图片上传
req.file 打印结果如下图:
Multer 实现本地文件/图片上传
每个文件(req.file)具有下面的信息:

属性描述说明
fieldnameField name 由表单指定
originalname用户计算机上的文件的名称
encoding文件编码
mimetype文件的 MIME 类型
size文件大小(字节单位)
destination保存路径可以在 DiskStorage 中设置
filename保存在 destination 中的文件名可以在 DiskStorage 中设置
path已上传文件的完整路径可以在 DiskStorage 中设置
buffer一个存放了整个文件的 Buffer可以在 MemoryStorag 中设置

3. 方法

3.1 multer(options).single(fieldname)

上传单个文件内容,如一次只上传一张图片。fieldname为上传时文件的字段名称。

//上传单个图片
let upload=multer({dest:"attachment/"}).single("photo");

上传的数据格式如下:
Multer 实现本地文件/图片上传

3.2 multer(options).array(fieldname[,maxCount])

适用于同一个字段,一次上传多个文件的情况,例如发状态时,选择多张图片发送。接受一个以 fieldname 命名的文件数组。可以指定 maxCount 来限制上传的最大数量。这些文件的信息保存在 req.files。

//一次最多上传3个文件
let upload=multer({dest:"attachment/"}).array("photo",3);

上传的数据格式如下:
Multer 实现本地文件/图片上传

3.3 multer(options).fields(fields)

适用于上传多个字段的情况。接受指定 fields 的混合文件。这些文件的信息保存在 req.files。fields 是一个对象数组,具有 name 和可选的 maxCount 属性。

let fieldsList=[
    {name:"photo1"},
    {name:"photo2",maxCount:2}
]
let upload=multer({dest:"attachment/"}).fields(fieldsList);

上传的数据格式如下:
Multer 实现本地文件/图片上传

3.4 multer(options).none()

接收只有文本域的表单,如果上传任何文件,会返回 “LIMIT_UNEXPECTED_FILE” 错误。

let upload=multer({dest:"attachment/"}).none();

3.5 multer(options).any()

接收一切上传的文件。

let upload=multer({dest:"attachment/"}).any();

4. multer(options) 配置项

Multer 接受一个 options 对象,其中最基本的是 dest 属性,这将告诉 Multer 将上传文件保存在哪。如果省略 options 对象,这些文件将保存在内存中,永远不会写入磁盘,options 配置如下:

属性值描述
dest or storage在哪里存储文件
limits限制上传数据的大小
fileFilter文件过滤器,控制哪些文件可以被接受
preservePath保存包含文件名的完整文件路径

4.1 dest

指定上传文件的存储路径。文件名默认为随机字符。如果想自定义文件名称, 使用下面 DiskStorage 来配置。

var upload = multer({dest:"attachment/"});

4.2 storaged 存储引擎

DiskStorage 磁盘存储引擎

磁盘存储引擎可以让你控制文件的存储。有两个属性,属性值都是函数。destination,指定文件存储的路径;filename,指定文件的存储名称。

const multer=require("multer");
const path=require("path");

//获取绝对路径
let fullPath=path.resolve(__dirname+"/attachment");
//设置文件的名称
let filename="";
let storage=multer.diskStorage({
	//设置存储路径
    destination:(req,file,cb)=>{
        console.log("destination:",file);//打印结果如下图
        cb(null,fullPath);
    },
    //设置存储的文件名
    filename:(req,file,cb)=>{
        console.log("filename:",file);//打印结果如下图
        //获取文件的扩展名
        let extname=path.extname(file.originalname);
        filename=file.fieldname+"-"+Date.now()+extname;
        cb(null,filename);
    }
})
let upload=multer({storage});

参数 file 中包含以下内容:
Multer 实现本地文件/图片上传
MemoryStorage 内存存储引擎

  • 内存存储引擎将文件存储在内存中的 Buffer 对象,它没有任何选项。
  • 当使用内存存储引擎,文件信息将包含一个 buffer 字段,里面包含了整个文件数据。
  • 当使用内存存储,上传非常大的文件,或者非常多的小文件,会导致你的应用程序内存溢出。
var storage = multer.memoryStorage()
var upload = multer({storage})

4.3 limits

用来指定一些数据大小的限制,设置 limits 可以帮助保护你的站点抵御拒绝服务 (DoS) 攻击。

属性值类型默认值描述
filesNumber无限在 multipart 表单中,上传文件的最大数量
fileSizeNumber无限上传时,每一个文件最大长度 (单位:bytes)
fieldsNumber无限非文件 field 的最大数量(提交表单时,可以提交非文件的字段的数量)
fieldNameSizeNumber100 bytes上传时,每一个 field 名字的最大长度
fieldSizeNumber1048576 bytes,即1MB上传时,每一个 field 的最大长度
partsNumber无限在 multipart 表单中,part 传输的最大数量(fields + files)
headerPairsNumber2000在 multipart 表单中,键值对最大组数
const multer=require("multer");
let upload=multer({
        limits:{
        	files:2, //最多上传2个文件
            fileSize:5120 //设置单个文件最大为 5kb
        }
    });

4.4 fileFilter

fileFilter 为一个函数,用来控制什么文件可以上传以及什么文件应该跳过。

function fileFilter (req, file, cb) {

  // 通过调用cb,用boolean值来指示是否应接受该文件

  // 拒绝这个文件,使用`false`,像这样:
  cb(null, false)

  // 接受这个文件,使用`true`,像这样:
  cb(null, true)

  // 如果有问题,你可以总是这样发送一个错误:
  cb(new Error('I don\'t have a clue!'))

}

5. 错误处理机制

当遇到一个错误,multer 将会把错误发送给 express。如果你想捕捉 Multer 错误,你可以使用 multer 对象下的 MulterError 类 (即 err instanceof multer.MulterError)。

var multer = require("multer")
var upload = multer().single("photo")

upload(req, res, function (err) {
	if (err instanceof multer.MulterError) {
	  // 捕捉 Multer 错误
	} else if (err) {
	  // 捕捉 express 错误
	} else {
	  // 上传成功
	}
})

6. 完整案例

项目结构如下:
Multer 实现本地文件/图片上传
代码如下:

//index.js
const express=require("express");
const app=express();
const uploadFile=require("./uploadfile");

//使用uploadFile中间件
app.post("/upload",uploadFile,(req,res)=>{
    console.log(req.body);
    //将req.body里的数据存储到数据库
    res.send("文件上传成功");
})
app.listen(3000);
//uploadFile.js
const multer=require("multer");
const path=require("path");

module.exports=(req,res,next)=>{
    let fullPath=path.resolve(__dirname+"/attachment");
    let filename="";
    let storage=multer.diskStorage({
    	//设置文件存储路径
        destination:(req,file,cb)=>{
            cb(null,fullPath);
        },
        //设置文件存储名称
        filename:(req,file,cb)=>{
            let extname=path.extname(file.originalname);
            filename=file.fieldname+"-"+Date.now()+extname;
            cb(null,filename);
        }
    })
	//上传单张图片
    let upload=multer({storage}).single("photo");
    upload(req,res,(err)=>{
       if (err instanceof multer.MulterError) {
            res.send("multererr:"+err);
        }else if(err){
            res.send("err:"+err);
        }else{
        	//上传成功后,将图片写在req.body.photo中,继续住下执行
            req.body.photo=filename;
            next();
        }
    })
}

7. 前端代码

简单写个例子,在前端试一下

<form action="http://localhost:3000/upload" method="POST" enctype="multipart/form-data">
	<p>
		<img width="80" src="" alt="">
		<input type="file" name="photo">
	</p>
	<p>
		<input type="text" name="desc" placeholder="请输描述信息">	
	</p>
	<button type="submit">提交</button>
</form>
<script>
	let $img=document.getElementsByTagName("img")[0];
	let $input=document.getElementsByName("photo")[0];
	$input.addEventListener("change",changeHandler);
	function changeHandler(){
		//显示选中的图片
		let f=$input.files[0];
		let src=window.URL.createObjectURL(f);
		$img.src=src;
	}
</script>

参考资料:https://www.npmjs.com/package/multer

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐