WEB前端开发技术杂谈

在Express中使用multer上传文件

2018-10-22  本文已影响14人  BigDipper

参考地址

概述

上传文件是web开发中经常要用到的功能。这篇文章就是介绍在Express中如何使用multer中间件进行文件上传。

使用的技术栈

开发过程

1. 先把项目构造出来

首先用一行代码,把环境搭起来。

npm install --save express multer

然后新建项目的入口文件app.js,代码如下:

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

// 静态化资源

app.use(express.static(path.join(__dirname, 'public')))

app.get('/', (req, res) => {
    res.send('首页');
});

app.listen(3000, () => console.log('服务器已启动!'));

在命令行启动项目,在浏览器中就可以看到首页面:

node app
首页面.png

2. 引入前端用到的上传页面和脚本

之后新建index.htmldemo.js文件,目录结构,如图所示:

目录结构.png

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>首页</title>
</head>
<body>
    <input type="file" id="myFile"/>
    <script src="/js/demo.js"></script>
</body>
</html>

demo.js(为演示方便,代码并没有考虑fetch的兼容性问题):

document.querySelector('#myFile').onchange = event => {
    const e = event || window.event;
    const target = e.target || e.srcElement;
    const file = target.files[0];
    const formdata = new FormData();

    formdata.append('myFile', file);    // 添加上传的文件对象
    
    fetch('/upload', {                  // 上传路径
        method: 'POST',
        body: formdata,
    })
    .then(res => res.json())
    .then(res => alert(res.message))
    .catch(err => console.dir(err));  
};

这时我们再回头来修改app.js的首页路由代码,以加载index.html页面:

const fs = require('fs');

app.get('/', (req, res) => {
    const html = fs.readFileSync('./view/index.html', { encoding: 'utf8' });  // 加载进行上传操作的页面

    res.send(html);
});

此时,首页如图所示:


引入前端资源.png

3. 用multer吧

好了,重头戏来了。

为了出彩,我们必须要修改一下app.js了,把multer模块引进来,并用它来接收上传的文件。光说不练,瞎扯淡,少废话,先上代码:

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

const storage = multer.diskStorage({        // 设置multer参数,个性化指定上传目录和文件名
    destination: (req, file, cb) => {
        const uploadFloder = './myUpload';  // 保存上传文件的目录

        try {
            fs.accessSync(uploadFloder);
        } catch (error) {
            fs.mkdirSync(uploadFloder);
        }

        cb(null, uploadFloder);
    },
    filename: (req, file, cb) => {
        cb(null, file.originalname);
    }
});
const upload = multer({                     // 实例化multer对象
    storage: storage
});

// 静态化资源

app.use(express.static(path.join(__dirname, 'public')))

app.get('/', (req, res) => {
    const html = fs.readFileSync('./view/index.html', { encoding: 'utf8' });  // 进行上传操作的页面

    res.send(html);
});

// 响应上传请求

app.post('/upload', upload.single('myFile'), (req, res) => {
    res.send({
        message: '响应了请求'
    });
});

app.listen(3000, () => console.log('服务器已启动!'));

这样就可以保存上传的文件了,有图有真相:


上传文件和响应状态.png

项目的结构:


上传的文件.png

好了,上传成功了,真相图也看了,现在该讲讲上面这些代码都是干什么用的了。

const multer = require('multer');

引入multer中间件。

const storage = multer.diskStorage({        // 设置multer参数,个性化指定上传目录和文件名
    destination: (req, file, cb) => {
        const uploadFloder = './myUpload';  // 保存上传文件的目录

        try {
            fs.accessSync(uploadFloder);
        } catch (error) {
            fs.mkdirSync(uploadFloder);
        }

        cb(null, uploadFloder);
    },
    filename: (req, file, cb) => {
        cb(null, file.originalname);
    }
});

在此处进行个性化的设置,指定上传的目录和文件名。这一步并不是必须要做的。如果不设置,则生成的文件名是一个哈希值。

const upload = multer({                     // 实例化multer对象
    storage: storage
});

使用刚才的设置来实例化对象。如果不个性化设置,则必须要使用dest属性来指定上传的路径,就像这样:

const upload = multer({                     // 实例化multer对象
    dest: './myUpload'                        // 保存上传文件的目录
});
app.post('/upload', upload.single('myFile'), (req, res) => {
    res.send({
        message: '响应了请求'
    });
});

使用single()方法来响应单文件上传操作。注意:此处的myFile参数是前端上传的文件名,必须要一致。


基因突变

如何上传多个文件?

上面的例子演示了单文件的上传操作,那么能不能同时上传多个文件呢?那肯定是能啊,只要把single()方法换成array(文件名, 最大文件个数)就行了。

首先,我们先向页面添加multiple属性,使其支持多文件上传:

<input type="file" id="myFile" multiple="multiple" />

然后修改demo.js文件,将上传的多个文件放入formdata中,这些文件都使用同一个文件名myFile,代码如下:

document.querySelector('#myFile').onchange = event => {
    const e = event || window.event;
    const target = e.target || e.srcElement;
    const files = target.files;
    const formdata = new FormData();

   for (const file of files) {

        // 添加上传的文件对象
        // formdata的append()方法有一个特点,
        // 它会把新值添加到已有值集合的后面,而不会用新值覆盖已有的值。
        // 这样就能达到用同一文件名,添加多个文件的目地。

        formdata.append('myFile', file);
    }
    
    fetch('/upload', {  // 上传文件
        method: 'POST',
        body: formdata,
    })
    .then(res => res.json())
    .then(res => alert(res.message))
    .catch(err => console.dir(err));  
};

最后,修改app.js文件,使用array()方法保存上传的多个文件,修改如下:

app.post('/upload', upload.array('myFile', 10), (req, res) => {
    res.send({
        message: '响应了请求'
    });
});

就是这么简单,就是这么拉风。

上一篇下一篇

猜你喜欢

热点阅读