【翻译】使用node.js和express实现简单的文件上传服务

原文链接:https://attacomsian.com/blog/uploading-files-nodejs-express

大量移动应用和网站允许用户上传账号头像等文件。因此,使用 Node.js 和 express 处理文件上传是一个很常见的 REST API 开发场景。在这个教程中,我们将讨论如何使用 Node.js 和 express 处理单个、多个文件上传,并且将上传的文件保存到服务器的指定位置。

初始化

首先,通过运行以下命令创建一个新的 node.js app。我使用的是 npm,你也可以根据喜好使用 yarn。

# 创建一个新的目录并进入
$ mkdir files-upload && cd files-upload

# 创建新的 app
$ npm init -y

# 或者使用 yarn 创建新的 app
$ yarn init -y 

-y 或 --yes 跳过了交互步骤并根据你的默认信息创建 package.json。下一步,运行以下命令安装需要的依赖:

# npm运行以下命令
$ npm install express body-parser cors express-fileupload morgan lodash --save

# 或者使用yarn
$ yarn add express body-parser cors express-fileupload morgan lodash 

以下是各组件的功能简述:

  • express - Node.js 上流行的 web 框架。我们将使用它来开发 REST API。
  • body-parser - Node.js 请求 body  解析器,可在你的 handler 之前解析传入的请求体,并且使其可通过 req.body 属性访问。简而言之,简化传入的请求。
  • cors - 另一个 Express 中间件,用于启用 CORS 跨域请求。 
  • express-fileupload - 用于上传文件的简单的 Express 中间件。它可以解析 multipart/form-data 请求, 如果有文件的话会提取文件并且使其可通过 req.files 属性访问。
  • morgan - 用于记录HTTP请求日志的 Node.js 中间件。
  • lodash - 一个提供数组、数字、对象、字符的工具函数的 JavaScript 库。

创建 Express 服务器

安装完需要的依赖项后,我们开始创建 Express 服务器。

index.js

const express = require('express');
const fileUpload = require('express-fileupload');
const cors = require('cors');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const _ = require('lodash');

const app = express();

// 启用文件上传
app.use(fileUpload({
    createParentPath: true
}));

//添加其他中间件
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(morgan('dev'));

//启动app
const port = process.env.PORT || 3000;

app.listen(port, () => 
  console.log(`App is listening on port ${port}.`)
);

上述代码应该还是比较好理解的。首先它设置了 express-fileupload 中间件来支持 multipart/form-data 请求. 然后, 其他 Express 被添加来允许跨域 (CORS), 请求体解析, 以及 HTTP 请求日志。最后,它在端口3000启动服务器。

上传单个文件

我们来创建我们的第一条路由,来允许用户上传他们的账户头像。

app.post('/upload-avatar', async (req, res) => {
    try {
        if(!req.files) {
            res.send({
                status: false,
                message: 'No file uploaded'
            });
        } else {
            //Use the name of the input field (i.e. "avatar") to retrieve the uploaded file
            let avatar = req.files.avatar;
            
            //Use the mv() method to place the file in upload directory (i.e. "uploads")
            avatar.mv('./uploads/' + avatar.name);

            //send response
            res.send({
                status: true,
                message: 'File is uploaded',
                data: {
                    name: avatar.name,
                    mimetype: avatar.mimetype,
                    size: avatar.size
                }
            });
        }
    } catch (err) {
        res.status(500).send(err);
    }
});

以上代码片段是一个 HTTP POST 方法。当你发送一个 multipart/form-data 请求到 /upload-avatar 路由来上传一个文件,这个方法将文件存储到服务器的 uploads 文件夹。

express-fileupload 中间件原理?

它使得上传的文件可以通过 req.files 属性访问到。例如如果你上传的文件名为 my-profile.jpg, 然后你的field name是 avatar, 你可以通过 req.files.avatar 访问到该文件。此 avatar 对象包括以下信息:

  • avatar.name - 上传的文件名,如 my-profile.jpg
  • avatar.mv - 此方法将文件移到服务器的其他路径
  • avatar.mimetype - 文件的 mime-type
  • avatar.size - bytes单位的文件大小
  • avatar.data - 文件的buffer呈现

上传多个文件

我们来创建另一个路由来允许用户一次上传多个照片。

app.post('/upload-photos', async (req, res) => {
    try {
        if(!req.files) {
            res.send({
                status: false,
                message: 'No file uploaded'
            });
        } else {
            let data = []; 
    
            //遍历所有文件
            _.forEach(_.keysIn(req.files.photos), (key) => {
                let photo = req.files.photos[key];
                
                //将照片移动到指定文件夹
                photo.mv('./uploads/' + photo.name);

                //将文件信息写入data数组
                data.push({
                    name: photo.name,
                    mimetype: photo.mimetype,
                    size: photo.size
                });
            });
    
            //返回response
            res.send({
                status: true,
                message: 'Files are uploaded',
                data: data
            });
        }
    } catch (err) {
        res.status(500).send(err);
    }
});

以上代码和单个文件上传很相似,除了我们现在收到的 field 是 photos 而不是 avatar。我们使用 lodash 下的  forEach() 和 keysIn()方法遍历 photos 并且将所有文件存入 uploads 目录下。

测试服务

大功告成!在终端项目根目录下,输入以下命令来启动应用:

$ node index.js 

应用将在端口 3000 启动。我们将使用 postman 来发送 multipart/form-data 请求:

1. 单个文件

Upload Single File

2. 多个文件

Upload Multiple Files

如果你想要让上传的文件能够被外界访问,只需要把 uploads 作为静态目录:

app.use(express.static('uploads'));

至此,你可以直接在浏览器中打开上传的文件:

http://localhost:3000/icon.png

限制文件大小

如果你想要限制一次上传的文件的总大小,将 limits 选项传入 express-fileupload 中间件:

app.use(fileUpload({
    createParentPath: true,
    limits: { 
        fileSize: 2 * 1024 * 1024 * 1024 //文件总大小上限2MB
    },
}));

源代码:https://github.com/attacomsian/code-examples/tree/master/nodejs/files-upload(MIT协议)

结论

以上就是我们如何使用 node.js 和 express 搭建一个简单的单文件/多文件上传服务! express-fileupload 是一个非常易用的处理文件上传的中间件。你也可以查看其文档来了解更多设置选项。 

posted on 2021-01-06 19:48  z_13  阅读(786)  评论(0)    收藏  举报

导航