常用的Express中间件multer: 上传文件

multer:用于处理 HTTP 请求中的 multipart/form-data 数据,通常用于上传文件。
在 package.json 中添加依赖项:

{
  "dependencies": {
    "express": "^4.18.2",
    "multer": "^1.4.2"
  }
}

const express = require('express');
const multer  = require('multer');

const app = express();
const upload = multer({ dest: 'uploads/' });

// 处理文件上传请求
app.post('/upload', upload.single('file'), (req, res) => {
  console.log(req.file); // 打印上传的文件信息
  res.send('File uploaded successfully');
});

// 处理其他中间件
// ...

app.listen(3000, () => {
  console.log('App started on port 3000');
});

在这个示例中,我们首先创建了一个 multer 实例,指定了上传文件的目标目录。然后,在处理文件上传请求的路由中,我们使用 upload.single('file') 方法来处理上传的文件,其中 'file' 是表单中文件上传字段的名称。处理上传文件的结果会保存在 req.file 中,我们可以通过这个对象来访问上传文件的信息。

需要注意的是,multer 中间件应该在其他中间件之前使用,以便能够正确地处理请求中的数据。此外,需要根据实际情况来设置上传文件的目标目录和文件名等选项

App started on port 3000
{
  fieldname: 'file',
  originalname: '-���\r  K�123.json',
  encoding: '7bit',
  mimetype: 'application/json',
  destination: 'uploads/',
  filename: '445a89e10c32e5c03eae9244ea0e1d82',
  path: 'uploads/445a89e10c32e5c03eae9244ea0e1d82',
  size: 158
}

默认的文件名生成函数如下:

function defaultFilename (req, file, cb) {
  crypto.pseudoRandomBytes(16, function (err, raw) {
    cb(err, err ? undefined : raw.toString('hex'))
  })
}

该函数使用 Node.js 内置的 crypto 模块生成一个 16 字节的伪随机字节序列,并将其转换为一个 32 个字符的十六进制字符串作为文件名。由于使用伪随机算法生成的字符串足够随机,因此可以保证文件名的唯一性。

服务器文件名存储策略

在服务器存储文件时,可以采用以下方法来生成合理的文件名:

时间戳:可以使用当前时间戳作为文件名,保证唯一性。但是时间戳本身没有意义,不便于后续管理和查找。

  • UUID:可以使用 UUID 作为文件名,保证唯一性。但是 UUID 较长,文件名可能过长。
  • 文件原始名称:可以使用文件的原始名称作为文件名。但是要注意中文名称的编码问题,避免出现乱码。
  • 文件名加上哈希值:可以使用文件名加上哈希值作为文件名,保证唯一性。哈希算法可以选择 MD5、SHA-1 等。但是哈希算法也不是绝对唯一的,有一定的概率会出现重复。
  • 文件名加上随机数:可以使用文件名加上随机数作为文件名,保证唯一性。但是随机数本身也不能完全保证唯一,有一定的概率会出现重复。
    综上所述,可以根据实际需求选择适合的方式生成合理的文件名。例如,如果需要快速查找文件,可以选择文件名加上哈希值或者 UUID;如果需要便于用户识别和管理,可以选择使用文件原始名称。
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/')
    },
    //上传文件的名称
    filename: function (req, file, cb) {
        let fileName = querystring.escape(file.originalname);
        console.log("qshell urlencode 结果一致"+fileName);
        cb(null, file.originalname)
    }
})
const upload =  multer({ storage: storage })
// 处理文件上传请求
app.post('/upload', upload.single('file'), (req, res) => {

output

qshell urlencode 结果一致%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D%20%20%E6%B5%8B%E8%AF%95123.json
{
  fieldname: 'file',
  originalname: '中文文件名  测试123.json',
  encoding: '7bit',
  mimetype: 'application/octet-stream',
  destination: 'uploads/',
  filename: '中文文件名  测试123.json',
  path: 'uploads/中文文件名  测试123.json',
  size: 158
}
$ qshell urldecode %E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D%20%20%E6%B5%8B%E8%AF%95123.json
中文文件名  测试123.json

配置文件大小限制

const multer = require('multer');

const upload = multer({
  limits: {
    fileSize: 1024 * 1024 * 5, // 限制文件大小为 5MB
  },
});

配置文件类型限制

const multer = require('multer');

const upload = multer({
  fileFilter: function(req, file, cb) {
    // 只允许上传 jpg, jpeg, png 和 gif 格式的图片
    if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
      return cb(new Error('只允许上传 jpg, jpeg, png 和 gif 格式的图片!'), false);
    }
    cb(null, true);
  },
});

在上面的示例代码中,fileFilter 函数中对上传的文件进行格式匹配,如果不符合要求则返回一个错误。如果文件符合要求,则调用 cb 函数来继续处理上传。注意,如果没有通过 cb 函数调用来处理上传,上传的文件将会被丢弃。

注意: postman测回中文乱码得常用curl 方式

https://github.com/expressjs/multer/issues/962 错误的编码在originalname包含unicode字符#