最终实现的效果,更改Input的值后,将图片显示出来、输入描述信息,提交后,图片上传到后台对应的路径下。
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方法,表示上传单个文件,参数为表单数据对应的keylet 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 中配置。
req.file 打印结果如下图:
每个文件(req.file)具有下面的信息:
3. 方法
3.1 multer(options).single(fieldname)
上传单个文件内容,如一次只上传一张图片。fieldname为上传时文件的字段名称。
//上传单个图片let upload=multer({dest:"attachment/"}).single("photo");
上传的数据格式如下:
3.2 multer(options).array(fieldname[,maxCount])
适用于同一个字段,一次上传多个文件的情况,例如发状态时,选择多张图片发送。接受一个以 fieldname 命名的文件数组。可以指定 maxCount 来限制上传的最大数量。这些文件的信息保存在 req.files。
//一次最多上传3个文件let upload=multer({dest:"attachment/"}).array("photo",3);
上传的数据格式如下:
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);
上传的数据格式如下:
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 配置如下:
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 中包含以下内容:
MemoryStorage 内存存储引擎
内存存储引擎将文件存储在内存中的 Buffer 对象,它没有任何选项。当使用内存存储引擎,文件信息将包含一个 buffer 字段,里面包含了整个文件数据。当使用内存存储,上传非常大的文件,或者非常多的小文件,会导致你的应用程序内存溢出。
var storage = multer.memoryStorage()var upload = multer({storage})
4.3 limits
用来指定一些数据大小的限制,设置 limits 可以帮助保护你的站点抵御拒绝服务 (DoS) 攻击。
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. 完整案例
项目结构如下:
代码如下:
//index.jsconst 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.jsconst 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>
参考资料:/package/multer