利用Vue3+Nodejs实现文件上传入门篇

 更新时间:2026年02月08日 11:14:09   作者:超级无敌大蟑王  
Node.js 和 Vue3 结合,通过文件分片、秒传检测和断点续传技术,为大文件上传提供了高效解决方案,这篇文章主要介绍了利用Vue3+Nodejs实现文件上传的相关资料,需要的朋友可以参考下

前言

最近在复习八股, 内容挺多的, 但是只看不练也没办法真正体会到八股的魅力, 今天来实现一个简易版的文件上传, 可能开始会比较粗糙简单, 但是里面的总结都是实践出来的, 让你深入体会到前后端是如何协作的

1.1 核心概念

什么是 multipart/form-data?`

当我们上传文件时,HTTP 请求需要使用 multipart/form-data 编码方式。这种方式可以将文件数据和普通表单字段一起发送。
请求标头的Content-Type字段如图所示:

1.2 前端实现

在前端 JavaScript 中,我们利用 FormData 来包装文件进行参数传输, FormData 不是一个普通的对象, 而是浏览器提供的一个Web API, 当服务端识别到前端传了这个对象的时候, 就会生成boundary分界线, 并且动态生成一串随机性极高的字符串

在发送请求时,不要手动设置请求头。 浏览器检测到 FormData 实例后,会自动配置正确的 Content-Type 并附带必要的 boundary 参数。

/**
 * 基础文件上传
 */
const uploadFile = async () => {
  if (!selectedFile.value) {
    message.value = '请先选择文件'
    return
  }

  const formData = new FormData()
  formData.append('file', selectedFile.value)

  try {
    message.value = '正在上传...'
    const res = await axios.post('http://localhost:3000/upload', formData)
    console.log(res.data)
    message.value = `上传成功: ${res.data.filename}`
  } catch (error) {
    console.log(error)
    message.value = '上传失败'
  }
}

重要提示:文件上传最好使用使用 axios 这个第三方库, 因为 axios 目前的技术在文件上传上很成熟, 可以解决请求头的配置并且可以不传formData对象就可以实现文件上传, fetch虽然是浏览器自带的API, 但是目前还是有部分瑕疵, 如果你在上传文件的时候特意配置了请求头multipart/form-data, 你们浏览器就会以为开发者已经解决了文件上传的问题, 就不会主动拼接 boundary

1.3 后端实现

原生的nodejs接收前端传来的文件是以二进制流的形式进行的, 直接处理流是非常复杂的,通常引入中间件 multer 来处理, multer可以自动匹配boundary, 不需要通过正则去匹配, 可能会导致文件损坏, multer可以将二进制文件和普通数据进行分离, 有利于后端对数据进行存储和修改

multer最早提供了一个配置简单的dest, 但是它带来了三个痛点

  1. 文件名无后缀并且文件名是随机生成的哈希值根本看不懂分不清, 并且储存的数据也不能直接打开, 乱码
  2. 只能存储在同一个文件夹下
  3. http协议默认使用Latin1解析, 导致文件名变成了???

multer.diskStorage是一个存储引擎, 它提供了两个核心的回调函数, 让你在文件写入硬盘的最后时刻进行拦截和修改

  1. destination, 控制文件的去向, 可以自定义将文件分开排放
  2. filename, 提取文件的后缀名并且拼接, 利用buffer修复乱码, 并且可以使用随机字符串来方式同文件覆盖
const express = require("express");
const app = express();
const cors = require("cors");
// 引入multer
const multer = require("multer");
const fs = require("fs"); 
const path = require("path");

// 修复cors中间件错误
app.use(cors());

// 文件保存失败
const uploadDir = path.join(__dirname, "uploads");
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir);
}

// 这种方式只能仿覆盖,文件后缀名丢失,无法修复乱码问题
// const upload = multer({
//   dest: uploadDir,
// });

// 配置 Multer 存储引擎
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    // 修复文件名乱码问题
    // Multer 处理 header 时默认用 latin1,需转回 utf8
    const originalName = Buffer.from(file.originalname, "latin1").toString(
      "utf8",
    );
    // 加上时间戳防止同名文件覆盖
    cb(null, Date.now() + "-" + originalName);
  },
});
// 这种方式能仿覆盖,文件后缀名完整,修复乱码问题
const upload = multer({ storage: storage });

app.post("/upload", upload.single("file"), (req, res) => {
  res.json({
    msg: "上传成功",
    filename: req.file.filename,
  });
});

app.listen(3000, () => {
  console.log("Server started on port 3000");
});

// 设置超时时间
server.timeout = 600000;

通过 multer 和 multer.diskStorage 进行配置存储引擎可以实现文件名保存,同一个文件的上传,区别如下

1.4 Vue 组件示例

在视图层,我们需要处理文件选择、上传状态(Loading)以及结果展示三个核心逻辑。

这段代码展示了如何通过 ref 获取 DOM 元素,并在异步操作期间锁定按钮状态,防止用户重复提交:

<script setup lang="ts">
import axios from 'axios'
import { ref } from 'vue'

const selectedFile = ref(null)
const message = ref('')

const uploadFileChange = (e) => {
  selectedFile.value = e.target.files[0]
  message.value = ''
}

const uploadFile = async () => {
  if (!selectedFile.value) {
    message.value = '请先选择文件'
    return
  }

  const formData = new FormData()
  formData.append('file', selectedFile.value)

  try {
    message.value = '正在上传...'
    const res = await axios.post('http://localhost:3000/upload', formData)
    console.log(res.data)
    message.value = `上传成功: ${res.data.filename}`
  } catch (error) {
    console.log(error)
    message.value = '上传失败'
  }
}
</script>

<template>
  <div>
    <input type="file" @change="uploadFileChange" />
    <button @click="uploadFile">文件上传</button>
    <p v-if="message">{{ message }}</p>
  </div>
</template>

<style scoped>
div {
  cursor: pointer;
}
</style>

1.5 常见 Bug 与解决方案

Bug 现象原因分析解决方案
请求体为空,后端收不到文件手动设置了 Content-Type 请求头删除手动设置的 Content-Type,让浏览器自动处理
大文件上传超时默认超时时间太短配置更长的超时时间,或使用分片上传
CORS 跨域错误前后端不同源后端配置 CORS 中间件 app.use(cors())

总结 

到此这篇关于利用Vue3+Nodejs实现文件上传入门篇的文章就介绍到这了,更多相关Vue3+Nodejs文件上传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • vue深拷贝的3种实现方式小结

    vue深拷贝的3种实现方式小结

    当使用同一个对象产生冲突时,可以使用lodash包,对该对象进行深拷贝,从而使操作的对象为不同的对象,这篇文章主要给大家介绍了关于vue深拷贝的3种实现方式,需要的朋友可以参考下
    2023-02-02
  • vue 解决路由只变化参数页面组件不更新问题

    vue 解决路由只变化参数页面组件不更新问题

    今天小编就为大家分享一篇vue 解决路由只变化参数页面组件不更新问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • vue下history模式刷新后404错误解决方法

    vue下history模式刷新后404错误解决方法

    这篇文章主要介绍了vue下history模式刷新后404错误解决方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • vue-router之nuxt动态路由设置的两种方法小结

    vue-router之nuxt动态路由设置的两种方法小结

    今天小编就为大家分享一篇vue-router之nuxt动态路由设置的两种方法小结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • 基于Vue3实现数字华容道游戏的示例代码

    基于Vue3实现数字华容道游戏的示例代码

    这篇文章主要为大家详细介绍了如何利用Vue编写一个数字华容道游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • vue 项目如何引入微信sdk接口的方法

    vue 项目如何引入微信sdk接口的方法

    本篇文章主要介绍了vue 项目如何引入微信sdk接口的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • Vue实现通知或详情类弹窗

    Vue实现通知或详情类弹窗

    这篇文章主要为大家详细介绍了Vue实现通知或详情类弹窗,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • el-table 动态合并不定项多级表头的方法

    el-table 动态合并不定项多级表头的方法

    本文主要介绍了el-table 动态合并不定项多级表头的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • ElementUI中el-dropdown-item点击事件无效问题

    ElementUI中el-dropdown-item点击事件无效问题

    这篇文章主要介绍了ElementUI中el-dropdown-item点击事件无效问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • vue过渡和animate.css结合使用详解

    vue过渡和animate.css结合使用详解

    本篇文章主要介绍了vue过渡和animate.css结合使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06

最新评论