nodejs multer实现文件上传功能全解(form上传、fetch请求上传、多文件上传)

3,652 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

你能够如何实现多文件的上传吗?你知道上传时Content-Type是什么格式吗?form上传和fetch链接上传有什么区别?

本文告诉你nodejs如何使用multer进行文件的上传、获取、处理,用具体的可运行的前后端代码教会你。

安装express和multer

npm i express multer -S

基础使用

前端表单

  1. enctype必须指定multipart/form-data,因为multer只支持这种。

  2. name的值“logo”对应服务器upload.single中的“logo”。

    <form action="http://localhost:3000/postFile" method="post" enctype="multipart/form-data">
        <input id="postFile" type="file" name="logo">
        <button type="submit">上传</button>
    </form>

后端服务器文件

  1. dest对应上传的文件的目录地址。

  2. upload.single的值“logo”对应前端name中的“logo”。

import express from 'express'
import multer from 'multer'

const app = express()

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

app.post('/postFile', upload.single('logo'), (req, res) => {
    res.send(req.file)
})

app.listen(3000, () => {
    console.log('服务器开启中')
})

启动服务。

在这里插入图片描述

去页面选择文件上传一张图片,上传成功。

在这里插入图片描述

配置上传文件名

我们发现虽然上传了,但是文件不是我们想要的样子,没有后缀,也不知道是我们上传的图片文件。

我们可以对multer进行详细的配置。

  1. destination配置上传文件的位置。

  2. filename配置文件名,可以利用file上传文件的内容进行配置。

import express from 'express'
import multer from 'multer'

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

const upload = multer({
    storage: multer.diskStorage({
        destination: function (req, file, cb) {
            cb(null, './uploads/')
        },
        filename: function (req, file, cb) {
            // fieldname是表单的name值,也就是我们设定的“logo”,
            // originalname是文件上传时的名字,可以根据它获取后缀,
            // encoding,mimetype 我就不详细介绍了,可以自行输出查看。
            const { fieldname, originalname, encoding, mimetype } = file
            const after = originalname.split('.')[1] ? '.' + originalname.split('.')[1] : '.jpg'
            cb(null, fieldname + after);
        }
    })
})

app.post('/postFile', upload.single('logo'), (req, res) => {
    res.send(req.file)
})

app.listen(3000, () => {
    console.log('服务器开启中')
})

然后我们重启服务器,再上传一次图片,就有了。

在这里插入图片描述

使用fetch上传文件

后端问题解决了我们看看前端的问题,表单上传文件不仅拓展差,还会跳转新页面,令人头疼。

我们肯定更希望用js中的fetch手动上传。如果还不会使用fetch可以先移步:js fetch异步请求使用详解

我们去掉form表单,自定义一个上传事件。

  1. 我的前端页面在8080端口,也做了nginx代理请求到3000端口,你们可以自行修改成自己的请求。

  2. body.append('logo', file)这里的作为key的“logo”代替了原本表单中的name值“logo”的作用。

  3. 虽然是post请求,但是不要添加请求头'Content-Type': 'multipart/form-data',上传文件时post已经自动帮你识别了,再加就要报错了。

<body>
    <input id="postFile" type="file" name="logo">
    <button type="button" onclick="upload()">上传</button>
</body>
<script>
    const upload = async () => {
        const body = new FormData()
        const file = document.getElementById('postFile').files[0]
        if (file) {
            body.append('logo', file)
            const response = await fetch('http://localhost:3000/postFile', {
                method: 'post',
                body
            })
            const res = await response.json()
            console.log(res)
        } else {
            alert('请选择文件!')
        }
    }
</script>

多文件上传

前端表单

  1. input加上multiple,支持多文件。

  2. 因为现在是多文件了,就不直接取文件,我们先获取用id获取dom,遍历添加进body,记得“logo”要对应后台“logo”。

<body>
    <input id="postFile" type="file" name="logo" multiple>
    <button type="sub" onclick="upload()">上传</button>
</body>
<script>
    const upload = async () => {
        const body = new FormData()
        const postFile = document.getElementById('postFile')
        if (postFile.files[0]) {
            for (const file of postFile.files) {
                body.append('logo', file)
            }
            const response = await fetch('http://localhost:3000/postFile', {
                method: 'post',
                body
            })
            const res = await response.json()
            console.log(res)
        } else {
            alert('请选择文件!')
        }

    }
</script>

后端服务器文件

  1. upload.single('logo')改成upload.array('logo', 3),后面的数字是限制上传文件数。

  2. 命名我们就用本来的名字,好区分不同的文件。

import express from 'express'
import mysql from 'mysql'
import multer from 'multer'

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

const upload = multer({
    storage: multer.diskStorage({
        destination: function (req, file, cb) {
            cb(null, './uploads/')
        },
        filename: function (req, file, cb) {
            const { fieldname, originalname, encoding, mimetype } = file
            // const after = originalname.split('.')[1] ? '.' + originalname.split('.')[1] : '.jpg'
            cb(null, originalname);
        }
    })
})

app.post('/postFile', upload.array('logo', 3), (req, res) => {
    res.send(req.files)
})

app.listen(3000, () => {
    console.log('服务器开启中')
})

尾言

大功告成,有帮助的话不妨点个赞吧,如果有什么问题可以评论区提出,会及时更新解决。