吐槽express 中间件multer

工作不是那么忙,想学一下Express+multer弄一个最简单的文件上传,然后开始npm install,然后开始对着multer官方文档一顿操作。

前台页面最简单的:

<!DOCTYPE html>
<html>

<head>
  <style>
  </style>
</head>

<body>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <input type="text" name="username" />
    <input type="file" name="avatar" />
    <input type="submit" value="提交">
  </form>
</body>

</html>

  后台服务启用static静态文件中间件,直接访问,然后提交到/upload,后台代码如下:

const express = require('express')
const multer = require('multer')
const uuid = require('uuid/v4')
const path = require('path')
const port = 3000
const app = express()
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, '../src/uploads'))
  },
  filename: function (req, file, cb) {
    console.log(file)
    let extName = path.extname(file.originalname)
    cb(null, uuid() + extName)
  }
})
var upload = multer({
  storage: storage
})
app.use(express.static('../src/test'))
app.use('/upload', upload.single('avatar'), (req, res) => {
  // 处理上传之后的逻辑
})
app.listen(port, () => {
  console.log('server is listening at ' + port)
})

就这么简单,它就好像自动就给传上去了,但是不足的地方也是存在的,比如默认配置下:它不给带文件默认的扩展名,什么类型的也都接收,然后也不限制大小

第一、首先说一下配置路径和怎么给上传之后的文件带上默认扩展名。

upload = multer({}),multer初始化的时候,如果文件路径dest不指定,那么官方文档说文件路径默认就是系统默认当前路径做为文件存储的临时路径,但是我尝试之后,发现没有报错,但是文件给上传到哪里去了,也不知道。满脸黑线!!!

然后按照官方文档,配置一下路径吧,可以直接multer({dest:'路径'}),也可以这样:

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, '../src/uploads'))
  },
  filename: function (req, file, cb) {
    console.log(file)
    let extName = path.extname(file.originalname)
    cb(null, uuid() + extName)
  }
})
var upload = multer({
  storage: storage
})

  destination回调函数指定文件上传路径,也可以根据file的不同类型,区分不同的路径,这逻辑都取决于你自己。filename也是回调函数,上传文件怎么命名也都取决于你,它默认上传后不给带原文件扩展名,所以这部分就需要你自己给处理一下了,我这边就先拿到文件原有的扩展名,然后给上传之后的文件加上。

第二、使用fileFilter来过滤允许上传的文件类型。

multer({})配置项中除了storage之外还给出了fileFIlter属性,用来过滤允许上传的文件,它也是一个函数,根据不同的文件后缀名来选择是否允许通过。

var upload = multer({
  storage: storage,
  fileFilter: function (req, file, cb) {
    let extName = path.extname(file.originalname)
    if (extName.includes('.png')) {
      cb(null, true)
    } else {
      // req.fileCheckError = {}
      // req.fileCheckError['fileFilter'] = '只能上传png格式的文件'
      cb(null, false)
    }
  }
})

  通过cb(null,true),第二个参数是true和false来确定是否允许通过,然后官方文档,还说第一个参数可以指定new Error来抛出一个错误,但是抛出错误之后,恐怕就需要另外写express的错误事件处理了,否则后台报错,前台是看不到东西的。官方又说话了,说multer自己不处理错误,它把错误委托给express处理了,然后用法就要变一变了,应该这样:

app.use('/upload', upload.single('avatar'), (req, res) => {
  upload(req, res, function (err) {
    if (err instanceof multer.MulterError) {
      console.log(err, 'multer error') //处理multer自身的错误
      res.send(err)
    } else if (err) {
      console.log('normal error', err) // 处理委托给express和上传时express自身的错误
      res.send(err.Error)
    } else if (Object.keys(req.fileCheckError || {}).length > 0) {
      console.log('req.fileCheckError', req.fileCheckError)
      res.send(JSON.stringify(req.fileCheckError))
    } else {
      console.log('req', req.file)
      let resContent = {}
      resContent['username'] = req.body.username
      resContent['filename'] = req.file.filename
      res.send(resContent)
    }
  })
})

  这样写原以为cb(new Error("错误信息"),false)的错误信息会交给multer的错误处理呢,谁知道人家给委托给express的错误处理了,即便是这样,它给的是一个错误,直接扔给前端,我想要的是一个友好的提示信息,而不是扔出一大坨错误信息,那就没有办法了吗?

这个时候,有高手给出招了,说你既然中间件可以对req进行操作,为什么不对req中增加一个属性呢?一句点醒梦中人,然后fileFilter中就给req加了fileCheckError,然后再express的错误处理的时候判断一下,如果有,就友好的交给前端。

三、限制大小。

multer({limits:{}}),options里面有一个limits配置项,它同样是一个对象里面有一堆配置的东西:

fieldNameSizeMax field name size100 bytes
fieldSizeMax field value size1MB
fieldsMax number of non-file fieldsInfinity
fileSizeFor multipart forms, the max file size (in bytes)Infinity
filesFor multipart forms, the max number of file fieldsInfinity
partsFor multipart forms, the max number of parts (fields + files)Infinity
headerPairsFor multipart forms, the max number of header key=>value pairs to parse2000

 

主要用到的也就是fileSize吧,超过设置大小,multer自动抛出错误到上面的multer自身处理错误中去,然后友好的发给前端就好了。

当然,以上说的这些错误,前端就可以判断了,比如类型、大小,但是都说前端的校验容易被篡改被突破,所以后端还是要校验的,毕竟网络安全无小事,万一呢。

 

转载于:https://www.cnblogs.com/liujiekun/p/11195913.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值