使用multer上传,处理和存储文件:逐步手册
#node #express #mongodb #multer

存储文件的三种基本方法:

  1. 将其直接存储在数据库中。
  2. 将其存储在文件系统中并保存到DB的路径。
  3. 将其存储在某些云存储中,例如Amazon S3,Google Cloud Storage或Microsoft Azure Blob存储,并保存到DB的路径。

每个都有其特定优势:安全性,文件管理,备份等。每个都有缺点:可伸缩性,成本和隐私。

因此,没有总体上最好的方法。相反,最佳方法随您所需的目标和周围环境而异。

上传和存储文件在像Amazon S3这样的云存储上已被广泛介绍,并且由于我永远不会建议将文件直接存储在您的数据库上,因此我将在这篇文章中谈论的方法将其直接保存到您的文件系统中。<<<<<<<<<<<<<<<< /p>

在设计软件解决方案时,没有什么比现场体验更像

几个月前,我的国家是其历史上最具竞争力的总统大选。我已经签署了一名政治弱者的志愿者(另一天的故事)。

我分配的任务是在有技术瓶颈时支持其他志愿者。从我们到达D-Day的那一刻起,所有内容(用于跟踪选举结果的软件,仪表板,分析,通信渠道等)都很好。

反对派变得阴暗。他们是现任人,有权这样做。他们正在调整结果并上传更改的结果。那是当我们意识到单独获取数字还不够的时候,您还需要结果的快照。

首先,我们存储了从供稿上的代理商那里收到的所有文件,并在Google驱动器上做出了贡献并尝试重命名它们(我知道复杂的过程) - 这就是我将与我分享的文件上传系统的原因你今天。

如何使用Multer存储文件。

multer是用于处理多部分/form-data的node.js middleware。表单是上传文件的用户最友好的方法。

multer也是其替代方案中最受欢迎的,那是因为它非常强大,并使用busboy有效地处理文件。

可悲的是,NPM页面上几乎没有任何有用的信息。

这是本指南的差距。

在这里,您将学习有关Multer需要了解的所有内容,以开始使用Node.js,
Express和MongoDB。让我们深入研究。

注意:本教程的重点是使用Multer,而不是使用CSS/HTML/NODEJS甚至MongoDB。如果您需要这些,请使用YouTube,freecodecamp,或咨询书籍**。

在前端

  1. 创建您的文件上传页面
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <p id="feedback-message"></p>
    <form
      action="/upload"``
      method="POST"
      id="uploadForm"
      enctype="multipart/form-data"
    >
      <label for="File">File: </label>
      <input type="file" name="avatar" />
      <br />
      <input type="submit" value="Upload File" />
    </form>
  </body>
</html>

让我们谈谈上述代码块

您在上面看到的代码是基本的HTML页面。

  • 它具有A 形式 元素。
  • 在该表单元素中是文件选择字段和提交按钮
  • 最后,在表单元素之前的段落标签 显示提交状态:成功或失败。

这里常见的痛苦错误是:

  1. 忘记“ Enctype” 属性。始终将其设置为“ multipart/form-data” 。 Multer不会处理任何不是多部分的形式(Multipart/form-data)。
  2. 忘记包含 name 属性:这就是帮助multer组相应地在服务器上收回的文件的原因。
  3. 缺乏用户反馈:在文件上传后,向用户提供明确而有用的反馈。这有助于他们了解上传是否成功或是否发生任何错误。

所有的一切都到位,让我们越过服务器端。

在服务器端:

  • 使用NPM安装multer
npm i multer

然后将其导入您的服务器根文件

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

  • 初始化和设置Multer

有两种使用Multer的方法:

  • 基本和
  • 自定义。

在基本中,您只能设置三个属性:

  1. dest: 存储位置
  2. 限制: 在字节中测量,并将“ filesize ”作为属性。
  3. filefilter: 用于根据某些条件过滤上传的 (在此示例中,我们使用了文件扩展名)。

这就是外观:

const upload = multer({
    dest: 'public/users-avatar',
//destination folder is automatically created if it's not available
    limits: {
        fileSize: 5000000 // 5mb
    },
    fileFilter: (req, file, callback) => {
        console.log(file);
        if (!file.originalname.match(/\.(png|jpeg|jpg)$/)) {
            return callback(new Error('Please upload a Picture(PNG or JPEG)'))
        }
        callback(undefined, true);
    }

})

这就是基本配置。

但是,自定义存储为我们提供了额外的选择,例如更改文件名等,但这也意味着更长的代码来编写。

我们将稍后再谈论自定义方法。

  • 设置您的路线和文件处理程序
*
**
***
//code that comes before hidden for brevity.
app.get('/upload', (req, res) => {
    res.render('index');
})

app.post('/upload', upload.single('avatar'), (req, res) => {
    res.redirect('/upload');
    res.json({data: "success"})
})

app.listen(process.env.PORT, () => {
    console.log('Listening for requests...');
})

还记得我对 name 属性的说法吗?

设置请求处理程序时,将值传递给您的上传功能。这至关重要,因为Multer知道在请求对象中应注意的是哪个字段。

如果您的HTML表单中的文件字段名称值与您传递给服务器上载函数的名称值之间存在不匹配,则上传将失败。

what happened when I changed "_Avatar_" to "_Avata_"

文件上传和自定义

如果您的应用程序需要对您的文件上传进行更大的控制,则Multer还可以灵活地使用其他存储选项,而不是普通的香草 dest

Multer带有两个内置存储引擎:

  • diskstorage:
  • 记忆孔:

include 3rd-Party storage engines

您应该知道的快速提示:

如果未设置存储,并且DEST为DEST,则文件将存储在带有随机名称的本地文件系统上。如果两个都不设置,则文件将存储在内存中。

请参阅动作中的diskstorage:

它只有两个选项: 目标 文件名 。两者都是确定文件应存储何处的函数,AD他们接受三个参数:req,file和parkack。

在行动中看到它:

var storage = multer.diskStorage({
    destination: function (req, file, callback) {
        fs.mkdir('public/avatar', function (err) {
            if (err) {
                console.log(err.stack)
            } else {
                callback(null, './uploads');
            }
        })
    },
    filename: function (req, file, callback) {
        callback(null, file.fieldname + '-' + Date.now());
    }
});

以上代码块的快速概述:

  • 目的地:这用于确定应存储上传文件的目录。它也可以作为字符串给出,如上所示。如果未设置目的地,则使用操作系统的默认目录。

  • 文件名:这用于确定文件夹中应命名的文件。如果没有给出文件名,则将给出每个文件一个不包含任何文件扩展名的随机名称(这与您自然会使用 dest 没有什么不同。选项。)

What happens when you don't set the name

注意:

从上面的屏幕截图中,很明显,multer不会为您附加任何文件扩展名。您的功能应返回文件名加文件扩展名。否则,由于没有附加扩展名,因此它将不可读。

常见的痛苦错误

  1. 文件大小限制不足:定义适当的文件大小限制,以防止过度上传大型文件,这些文件可能会损害服务器资源并影响性能。
  2. 没有文件类型限制:指定可以上传的可接受的文件类型,以防止上传潜在有害或无关的文件。
  3. 缺乏验证:未能验证文件上传可能会导致安全漏洞。验证文件类型,大小和格式,以防止恶意文件上传。不要仅依靠客户端验证。
  4. 服务器端处理不足:确保服务器端代码正确处理上传的文件,包括检查错误,处理文件存储并执行任何必要的处理。

更重要的是,永远不要使Multer成为全局中间件,因为有不良意图的用户可以将文件上传到您没想到的路由,从而导致混乱。

所以这是一个不好的方法:

const multer = require(multer)
app.use(multer().single(photos)) //This is force multer to handle every request to your server

而是使用仅处理文件的路由上的上传功能。

最后一句话

对于大多数应用程序,我上面共享的内容就足够了。

,对于一些,需要进行更多的自定义,例如从同一字段上传多个文件或来自不同字段但同一表单的多个文件。

如果是您,请参见upload.array(), upload.fields(), and upload.none() methods。我将谈论处理错误,以在以后的帖子中获得更好的用户体验。

在那之前,再见。