最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用Vue3+Nodejs實(shí)現(xiàn)文件上傳入門篇

 更新時(shí)間:2026年02月08日 11:14:09   作者:超級(jí)無敵大蟑王  
Node.js 和 Vue3 結(jié)合,通過文件分片、秒傳檢測(cè)和斷點(diǎn)續(xù)傳技術(shù),為大文件上傳提供了高效解決方案,這篇文章主要介紹了利用Vue3+Nodejs實(shí)現(xiàn)文件上傳的相關(guān)資料,需要的朋友可以參考下

前言

最近在復(fù)習(xí)八股, 內(nèi)容挺多的, 但是只看不練也沒辦法真正體會(huì)到八股的魅力, 今天來實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的文件上傳, 可能開始會(huì)比較粗糙簡(jiǎn)單, 但是里面的總結(jié)都是實(shí)踐出來的, 讓你深入體會(huì)到前后端是如何協(xié)作的

1.1 核心概念

什么是 multipart/form-data?`

當(dāng)我們上傳文件時(shí),HTTP 請(qǐng)求需要使用 multipart/form-data 編碼方式。這種方式可以將文件數(shù)據(jù)和普通表單字段一起發(fā)送。
請(qǐng)求標(biāo)頭的Content-Type字段如圖所示:

1.2 前端實(shí)現(xiàn)

在前端 JavaScript 中,我們利用 FormData 來包裝文件進(jìn)行參數(shù)傳輸, FormData 不是一個(gè)普通的對(duì)象, 而是瀏覽器提供的一個(gè)Web API, 當(dāng)服務(wù)端識(shí)別到前端傳了這個(gè)對(duì)象的時(shí)候, 就會(huì)生成boundary分界線, 并且動(dòng)態(tài)生成一串隨機(jī)性極高的字符串

在發(fā)送請(qǐng)求時(shí),不要手動(dòng)設(shè)置請(qǐng)求頭。 瀏覽器檢測(cè)到 FormData 實(shí)例后,會(huì)自動(dòng)配置正確的 Content-Type 并附帶必要的 boundary 參數(shù)。

/**
 * 基礎(chǔ)文件上傳
 */
const uploadFile = async () => {
  if (!selectedFile.value) {
    message.value = '請(qǐng)先選擇文件'
    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 這個(gè)第三方庫(kù), 因?yàn)?axios 目前的技術(shù)在文件上傳上很成熟, 可以解決請(qǐng)求頭的配置并且可以不傳formData對(duì)象就可以實(shí)現(xiàn)文件上傳, fetch雖然是瀏覽器自帶的API, 但是目前還是有部分瑕疵, 如果你在上傳文件的時(shí)候特意配置了請(qǐng)求頭multipart/form-data, 你們?yōu)g覽器就會(huì)以為開發(fā)者已經(jīng)解決了文件上傳的問題, 就不會(huì)主動(dòng)拼接 boundary

1.3 后端實(shí)現(xiàn)

原生的nodejs接收前端傳來的文件是以二進(jìn)制流的形式進(jìn)行的, 直接處理流是非常復(fù)雜的,通常引入中間件 multer 來處理, multer可以自動(dòng)匹配boundary, 不需要通過正則去匹配, 可能會(huì)導(dǎo)致文件損壞, multer可以將二進(jìn)制文件和普通數(shù)據(jù)進(jìn)行分離, 有利于后端對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ)和修改

multer最早提供了一個(gè)配置簡(jiǎn)單的dest, 但是它帶來了三個(gè)痛點(diǎn)

  1. 文件名無后綴并且文件名是隨機(jī)生成的哈希值根本看不懂分不清, 并且儲(chǔ)存的數(shù)據(jù)也不能直接打開, 亂碼
  2. 只能存儲(chǔ)在同一個(gè)文件夾下
  3. http協(xié)議默認(rèn)使用Latin1解析, 導(dǎo)致文件名變成了???

multer.diskStorage是一個(gè)存儲(chǔ)引擎, 它提供了兩個(gè)核心的回調(diào)函數(shù), 讓你在文件寫入硬盤的最后時(shí)刻進(jìn)行攔截和修改

  1. destination, 控制文件的去向, 可以自定義將文件分開排放
  2. filename, 提取文件的后綴名并且拼接, 利用buffer修復(fù)亂碼, 并且可以使用隨機(jī)字符串來方式同文件覆蓋
const express = require("express");
const app = express();
const cors = require("cors");
// 引入multer
const multer = require("multer");
const fs = require("fs"); 
const path = require("path");

// 修復(fù)cors中間件錯(cuò)誤
app.use(cors());

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

// 這種方式只能仿覆蓋,文件后綴名丟失,無法修復(fù)亂碼問題
// const upload = multer({
//   dest: uploadDir,
// });

// 配置 Multer 存儲(chǔ)引擎
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    // 修復(fù)文件名亂碼問題
    // Multer 處理 header 時(shí)默認(rèn)用 latin1,需轉(zhuǎn)回 utf8
    const originalName = Buffer.from(file.originalname, "latin1").toString(
      "utf8",
    );
    // 加上時(shí)間戳防止同名文件覆蓋
    cb(null, Date.now() + "-" + originalName);
  },
});
// 這種方式能仿覆蓋,文件后綴名完整,修復(fù)亂碼問題
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");
});

// 設(shè)置超時(shí)時(shí)間
server.timeout = 600000;

通過 multer 和 multer.diskStorage 進(jìn)行配置存儲(chǔ)引擎可以實(shí)現(xiàn)文件名保存,同一個(gè)文件的上傳,區(qū)別如下

1.4 Vue 組件示例

在視圖層,我們需要處理文件選擇、上傳狀態(tài)(Loading)以及結(jié)果展示三個(gè)核心邏輯。

這段代碼展示了如何通過 ref 獲取 DOM 元素,并在異步操作期間鎖定按鈕狀態(tài),防止用戶重復(fù)提交:

<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 = '請(qǐng)先選擇文件'
    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 現(xiàn)象原因分析解決方案
請(qǐng)求體為空,后端收不到文件手動(dòng)設(shè)置了 Content-Type 請(qǐng)求頭刪除手動(dòng)設(shè)置的 Content-Type,讓瀏覽器自動(dòng)處理
大文件上傳超時(shí)默認(rèn)超時(shí)時(shí)間太短配置更長(zhǎng)的超時(shí)時(shí)間,或使用分片上傳
CORS 跨域錯(cuò)誤前后端不同源后端配置 CORS 中間件 app.use(cors())

總結(jié) 

到此這篇關(guān)于利用Vue3+Nodejs實(shí)現(xiàn)文件上傳入門篇的文章就介紹到這了,更多相關(guān)Vue3+Nodejs文件上傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

雷波县| 舟曲县| 乌拉特中旗| 全州县| 芜湖县| 正阳县| 岳阳市| 千阳县| 宣威市| 纳雍县| 南阳市| 巫溪县| 兴宁市| 丹江口市| 屏东县| 白银市| 临武县| 铁岭县| 铁岭市| 越西县| 天长市| 惠安县| 民勤县| 日照市| 舞阳县| 青海省| 东乡族自治县| 钟祥市| 商洛市| 松溪县| 洱源县| 芮城县| 屯昌县| 临漳县| 哈尔滨市| 门源| 册亨县| 栾城县| 波密县| 长治市| 常山县|