使用Express配合multer来实现文件上传功能

1.涉及依赖包

  • multer: 处理文件上传的
  • cors: 处理跨域的

2.http-server

一个简单的http服务器,经常用于本地测试和开发
安装

js 复制代码
// 全局安装
 sudo npm install http-server -g

使用

js 复制代码
// 在当前目录下建立http服务器,启动后可以直接打开输出内容里的ip地址
http-server .
// 指定ip和端口号http-server [path] [options]
http-server -a 127.0.0.1 -p 9090

启动后即可根据所启动服务器的地址来访问该服务下的资源,默认访问inex.html文件

3. 单文件上传

安装依赖

js 复制代码
npm install express multer cors

新建index.js文件,并输入代码创建express应用

js 复制代码
const express = require('express');
const multer = require('multer');
const cors = require('cors');

const app = express();
app.use(cors());

const upload = multer({ dest: 'files' });

app.post(
  '/upload',
  upload.single('aaa'),
  function (req, res, next) {
    console.log(req.file, 'file');
    console.log(req.body, 'body');
  },
  function (err, req, res, next) {}
);

app.listen(3333);

app.use是使用cors中间件来处理跨域。

multer处理文件上传,指定保存文件的目录是files。

因为multer本身是一个函数,所以不需要app.use。

upload.single是在处理单文件的时候使用single。

upload.single('aaa')是指接文件的参数名是aaa。

创建一个index.html文件来作为文件入口

js 复制代码
<!DOCTYPE html>
<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>
    <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
  </head>
  <body>
    <input id="fileInput" type="file" />
    <script>
      const fileInput = document.querySelector('#fileInput');

      async function formData() {
        const data = new FormData();
        data.set('name', 'yangmy');
        data.set('age', 20);
        data.set('file', fileInput.files[0]);

        const res = await axios.post('http://localhost:3333/upload', data);
      }

      fileInput.onchange = formData;
    </script>
  </body>
</html>

然后使用http-server在当前目录下启动一个http服务:

在当前目录下运行index.js文件:

js 复制代码
node index.js

在浏览器中打开http-server创建的服务地址,此时后默认打开index.html文件:

选一张图片上传:

此时可以看到浏览器的请求参数以及服务端打印的日志:

浏览器:

服务端:

然后就可以看到我们代码中就会多出一个files的文件夹,里面存放的是刚上传的问件:

4.多文件上传

index.js中添加一个新的路由,用于处理多文件上传:

js 复制代码
const express = require('express');
const multer = require('multer');
const cors = require('cors');

const app = express();
app.use(cors());

const upload = multer({ dest: 'files' });

app.post(
  '/upload',
  upload.single('file'),
  function (req, res, next) {
    console.log(req.file, 'file');
    console.log(req.body, 'body');
  },
  function (err, req, res, next) {}
);

app.post(
  '/uploads',
  upload.array('filelist', 2),
  function (req, res, next) {
    console.log(req.files, 'file');
    console.log(req.body, 'body');
  },
  function (err, req, res, next) {}
);

app.listen(3333);

这里修改了index.js文件,添加了/uploads接口,用作处理多文件上传。相比于单文件上传,修改了以下: upload.single('file')改成了upload.array('filelist', 2),因为要上传多文件,所以single变成了array,第二个数字参数是文件上传的数量限制。

新建一个multis.html用来当作多文件上传的页面,页面内容是:

js 复制代码
<!DOCTYPE html>
<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>
    <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
  </head>
  <body>
    as
    <input id="fileInput" type="file" multiple />
    <script>
      const fileInput = document.querySelector('#fileInput');

      async function formData2() {
        const data = new FormData();
        data.set('name', 'yangmy');
        data.set('age', 20);
        [...fileInput.files].forEach((item) => {
          data.append('filelist', item);
        });

        const res = await axios.post('http://localhost:3333/uploads', data);
        console.log(res);
      }

      fileInput.onchange = formData2;
    </script>
  </body>
</html>

重新运行项目:node index.js:

打开服务页面,路由中输入multis.html路由,然后上传两个图片文件:

此时访问的是多文件上传页面,接口参数中的filelist包含两个文件参数,再看控制台打印的日志: 如图:req.files打印出两个文件的数据

如果我们上传超过2个文件的数据呢?

上传超过规定的文件数量后,文件上传会失败,并不会上传到我们的files文件夹中。

在多文件上传的接口代码中加入一个错误处理的中间件:

此时可以在接口函数的第四个参数中拿到错误信息,把错误信息打印一下,展示如下:

我们可以通过这个报错的code来处理返回结果,在index.js的多文件上传接口后加上如下代码:

这样再次试试上传多个文件的情况: 此时便会根据错误处理的逻辑,当上传文件数量过多时接口会400,且返回to many file的提示

5.多个字段上传文件且限制不同

index.js文件中添加一个新的接口uploadFileds,作为上传多个字段,且限制不同的接口,代码如下:

js 复制代码
app.post(
  '/uploadFileds',
  upload.fields([
    { name: 'files1', maxCount: 2 },
    { name: 'files2', maxCount: 3 },
  ]),
  function (req, res, next) {
    console.log(req.files, 'file');
    console.log(req.body, 'body');
  },
  function (err, req, res, next) {
    console.log(err, 'err');
    if (err.code === 'LIMIT_UNEXPECTED_FILE') {
      res.status(400).end('to many files');
    }
  }
);

其中upload.fields指定了每个字段的字段名以及该字段名接收文件的限制,然后接收到请求后同样使用req.files来获取文件信息。

然后新建multisFileds.html文件,作为这个测试的页面,代码如下:

js 复制代码
<!DOCTYPE html>
<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>
    <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
  </head>
  <body>
    <input id="fileInput" type="file" multiple />
    <script>
      const fileInput = document.querySelector('#fileInput');

      async function formData2() {
        const data = new FormData();
        data.set('name', 'yangmy');
        data.set('age', 20);
        data.append('files1', fileInput.files[0]);
        data.append('files1', fileInput.files[1]);
        data.append('files2', fileInput.files[2]);
        data.append('files2', fileInput.files[3]);
        data.append('files2', fileInput.files[4]);

        const res = await axios.post(
          'http://localhost:3333/uploadFileds',
          data
        );
        console.log(res);
      }

      fileInput.onchange = formData2;
    </script>
  </body>
</html>

其中上传的字段名和接口中定义的都必须对应才可以。

访问multisFileds.html页面,并上传五张图片文件

上传成功后我们看到存放文件夹的文件确实多了五条数据,且,控制台也打印出这些文件的信息

6.不确定上传文件的字段

不确定上传文件的字段以及限制时,使用upload.any()来接收文件。

再次在index.js中新增一个接口:

js 复制代码
app.post(
  '/uploadfileNoname',
  upload.any(),
  function (req, res, next) {
    console.log(req.files, 'file');
    console.log(req.body, 'body');
  },
  function (err, req, res, next) {
    console.log(err, 'err');
    if (err.code === 'LIMIT_UNEXPECTED_FILE') {
      res.status(400).end('to many files');
    }
  }
);

复用multisFileds.html文件,将上传的接口改为uploadfileNoname

重新运行express应用,然后在浏览器中打开multisFileds.html页面,选中文件上传

上传成功后看到files文件夹下面又多了5条文件数据

这时控制台日志打印的文件内容包含有所上传的文件信息,但是这次没有字段名,字段名都在文件信息中,需要一个个去遍历处理

7.保存上传的文件名

js 复制代码
const upload = multer({ dest: 'files' });

之前通过dest指定了保存文件的路径是files文件夹,现在修改一下,通过multer.diskStorage()方法来配置filenamedestination参数,使其将文件保存在指定的文件夹,且指定文件名和文件名后缀 在index.js中添加如下代码:

js 复制代码
const fs = require('fs');
const path = require('path');

const storage = multer.diskStorage({
  // 目录
  destination: (req, file, cb) => {
    try {
      fs.mkdirSync(path.join(process.cwd(), 'uploadFile'));
    } catch (e) {}
    cb(null, path.join(process.cwd(), 'uploadFile'));
  },
  // 文件名
  filename: (req, file, cb) => {
    cb(null, file.originalname);
  },
});
const upload = multer({ storage });

要注意destinationfilename中的回调函数cb的第一个参数是传的错误信息,所以这里要注意传null。

生成的storage要放到const upload = multer({ storage });中,这样上传时就会走写的那个方法了。

然后我们在上一个例子中使用上传功能,成功上传图片后,发现上传的图片出现在了定义的uploadFile文件夹下,且名字我们使用的是上传文件原本的名称

总结 :没有总结,这是我学习用来自己再实现一次,刷熟练度的地方,原文是光神写的小册《Nest通关秘籍》

相关推荐
炫饭第一名9 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
进击的尘埃11 小时前
Vue3 响应式原理:从 Proxy 到依赖收集,手撸一个迷你 reactivity
javascript
None32111 小时前
【NestJs】基于Redlock装饰器分布式锁设计与实现
后端·node.js
willow11 小时前
JavaScript数据类型整理1
javascript
LeeYaMaster11 小时前
20个例子掌握RxJS——第十一章实现 WebSocket 消息节流
javascript·angular.js
UIUV12 小时前
RAG技术学习笔记(含实操解析)
javascript·langchain·llm
颜酱13 小时前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
FansUnion14 小时前
我如何用 Next.js + Supabase + Cloudflare R2 搭建壁纸销售平台——月成本接近 $0
javascript
左夕15 小时前
分不清apply,bind,call?看这篇文章就够了
前端·javascript
滕青山16 小时前
文本行过滤/筛选 在线工具核心JS实现
前端·javascript·vue.js