Vue + Node.js 搭建「檔案上傳」管理後臺

語言: CN / TW / HK

本文完整版《 Vue + Node.js 搭建「檔案上傳」管理後臺

本教程手把手帶領大家搭建一套通過 Vue + Node.js 上傳檔案的後臺系統,只要你跟隨本教程一步步走,一定能很好的理解整個前後端上傳檔案的程式碼邏輯。前端我們使用 Vue + Axios + Multipart 來搭建前端上傳檔案應用,後端我們使用 Node.js + Express + Multer 來搭建後端上傳檔案處理應用。

當然,本教程還會教給大家如何寫一個可以限制上傳檔案大小、有百分比進度條、可報錯、可顯示伺服器上檔案列表、可點選下載檔案的前端操作介面。

最後完成的上傳檔案工具後臺如下圖,跟隨本教學習,你也可以搭出來。

如果你對前端不是很熟悉,不想寫前端,推薦使用卡拉雲搭建後臺管理系統,卡拉雲是新一代低程式碼開發工具,不用懂任何前端技術,僅靠滑鼠拖拽,即可快速搭建包括「上傳檔案」在內的任何後臺管理工具。立即試用卡拉雲1 分鐘搭建「檔案上傳」工具。詳情見本文文末。

Vue + Node.js「上傳檔案」前後端專案結構

Vue 前端部分

  • UploadFilesService.js:這個指令碼呼叫通過 Axios 儲存檔案和獲取檔案的方法

  • UploadFiles.vue:這個元件包含所有上傳檔案相關的資訊和操作

  • App.vue:把我們的元件匯入到 Vue 起始頁

  • index.html:用於匯入 Bootstrap

  • http-common.js:配置並初始化 Axios

  • vue.config.js:配置 APP 埠

Node.js 後端部分

  • resources/static/assets/uploads:用於儲存上傳的檔案

  • middleware/upload.js:初始化 Multer 引擎並定義中介軟體

  • file.controller.js:配置 Rest API

  • routes/index.js:路由,定義前端請求後端如何執行

  • server.js:執行 Node.js Express 應用

✦ 前端部分 - 上傳檔案 Vue + Axios + Multipart

配置 Vue 環境

使用 npm 安裝 Vue 腳手架 vue-cli

npm install -g @vue/cli

複製程式碼

然後我們建立一個 Vue 專案 kalacloud-vue-multiple-files-upload

vue create kalacloud-vue-multiple-files-upload

複製程式碼

安裝完成後,cd 進入 kalacloud-vue-multiple-files-upload 目錄,接下來所有操作都在這個目錄之下。

安裝 Axios:

npm install axios

複製程式碼

我們先跑一下 Vue ,這是 vue 的預設狀態

npm run serve

複製程式碼

我們可以看到瀏覽器裡 Vue 已經在 localhost:8080 跑起來了。

擴充套件閱讀:《 Vue 搭建帶預覽的「上傳圖片」管理後臺

匯入 Bootstrap 到專案中

開啟 index.html 把以下程式碼新增到 <head> 中:

檔案位置:public/index.html

<!DOCTYPE html><html lang="en"><head>...<link type="text/css" rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" /></head>  ...</html>

複製程式碼

初始化 Axios HTTP 客戶端

在 src 資料夾下,建立 http-common.js 檔案,如下所示:

檔案位置:src/http-common.js

import axios from "axios";export default axios.create({  baseURL: "http://localhost:8080",  headers: {    "Content-type": "application/json"  }});

複製程式碼

這裡的 baseURL 是你上傳檔案的後端伺服器 REST API 地址,請根據實際情況修改。本教程後文,教你搭建上傳檔案的後端部分,請繼續閱讀。

建立「上傳檔案」功能

我們來寫一個 JS 指令碼,這個指令碼呼叫 Axios 傳送 HTTP API 請求,與後端伺服器通訊。

這個指令碼包含 2 個功能

  • upload(file) : POST 資料到後端,再加一個上傳進度的回撥,可以放個上傳進度條。

  • getFiles() : 用於獲取伺服器上傳資料夾中的檔案列表

檔案位置:src/services/UploadFilesService.js

import http from "../http-common";class UploadFilesService {  upload(file, onUploadProgress) {    let formData = new FormData();    formData.append("file", file);    return http.post("/upload", formData, {      headers: {        "Content-Type": "multipart/form-data"      },      onUploadProgress});  }  getFiles() {    return http.get("/files");  }}export default new UploadFilesService();

複製程式碼

  • 首先匯入我們剛剛寫好的 Axios HTTP 配置檔案 http-common.js

  • FormData 是一種可將資料編譯成鍵值對的資料結構

  • Axios 的進度條事件, onUploadProgress 是用來監測上傳進度,顯示進度資訊

  • 最後我們呼叫 Axios 提供的 post() & get() 來向後端 API 傳送 POST & GET 請求

擴充套件閱讀:《 Vue Router 手把手教你搭 Vue3 路由

建立一個 Vue 多檔案上傳元件

接下來,我們來寫一個 Vue 上傳元件,這個元件要包含上傳檔案的所有基本功能,比如 上傳按鈕、進度條、提示資訊、基本 UI 等。

首先,建立一個 Vue 元件模版(UploadFiles.vue)然後把剛剛寫好的配置檔案(UploadFilesService.js)匯入進去。

檔案位置:src/components/UploadFiles.vue

<template></template><script>import UploadService from "../services/UploadFilesService";export default {  name: "upload-files",  data() {    return {    };  },  methods: {}};</script>

複製程式碼

然後在這裡定義 data() 變數

export default {  name: "upload-files",  data() {    return {      selectedFiles: undefined,      progressInfos: [],      message: "",      fileInfos: [],    };  },};

複製程式碼

接下來,我們定義 methods 讓  selectFiles() 從  <input type="file" > 中獲取選定的檔案。

export default {  name: "upload-files",  ...  methods: {    selectFile() {      this.progressInfos = [];      this.selectedFiles = event.target.files;    }  }};

複製程式碼

selectedFiles 用來訪問當前選定的檔案,每個檔案都有一個對應的進度條(百分比 &檔名)以及被  progressInfos 索引。

export default {  name: "upload-files",  ...  methods: {    ...    uploadFiles() {      this.message = "";      for (let i = 0; i < this.selectedFiles.length; i++) {        this.upload(i, this.selectedFiles[i]);      }    }  }};

複製程式碼

我們通過回撥 UploadFilesService.upload() 來獲得上傳資訊

export default {  name: "upload-files",  ...  methods: {    ...    upload(idx, file) {      this.progressInfos[idx] = { percentage: 0, fileName: file.name };      UploadService.upload(file, (event) => {        this.progressInfos[idx].percentage = Math.round(100 * event.loaded / event.total);      })        .then((response) => {          let prevMessage = this.message ? this.message + "\n" : "";          this.message = prevMessage + response.data.message;          return UploadService.getFiles();        })        .then((files) => {          this.fileInfos = files.data;        })        .catch(() => {          this.progressInfos[idx].percentage = 0;          this.message = "Could not upload the file:" + file.name;        });    }  }};

複製程式碼

  • 檔案上傳進度我們可以根據 event.loadedevent.total 來計算

  • 如果傳輸完成,我們呼叫 UploadFilesService.getFiles() 來獲取檔案資訊,並將結果更新到  fileInfos 裡,狀態是一個數組  {name, url}

我們還需要在 mounted() 中新增呼叫。

export default {  name: "upload-files",  ...  mounted() {    UploadService.getFiles().then((response) => {      this.fileInfos = response.data;    });  }};

複製程式碼

現在我們實現上傳檔案 UI 的 HTML 模板。將以下內容新增到 <template>

<template>  <div>    <div v-if="progressInfos">      <div class="mb-2"        v-for="(progressInfo, index) in progressInfos"        :key="index"      >        <span>{{progressInfo.fileName}}</span>        <div class="progress">          <div class="progress-bar progress-bar-info"            role="progressbar"            :aria-valuenow="progressInfo.percentage"            aria-valuemin="0"            aria-valuemax="100"            :style="{ width: progressInfo.percentage + '%' }"          >            {{progressInfo.percentage}}%          </div>        </div>      </div>    </div>    <label class="btn btn-default">      <input type="file" multiple @change="selectFile" />    </label>    <button class="btn btn-success"      :disabled="!selectedFiles"      @click="uploadFiles"    >      上傳    </button>    <div v-if="message" class="alert alert-light" role="alert">      <ul>        <li v-for="(ms, i) in message.split('\n')" :key="i">          {{ ms }}        </li>      </ul>    </div>    <div class="card">      <div class="card-header"> 檔案列表 </div>      <ul class="list-group list-group-flush">        <li class="list-group-item"          v-for="(file, index) in fileInfos"          :key="index"        >          <a :href="file.url">{{ file.name }}</a>        </li>      </ul>    </div>  </div></template>

複製程式碼

在上面的程式碼中,我們使用 Bootstrap 進度條,這裡不展開講了,更多細節可檢視Bootstrap 文件。

在 App.vue 中新增「檔案上傳」元件

開啟 App.vue ,在程式碼中匯入 UploadFiles 元件。

<template>  <div id="app">    <div class="container" style="width:600px">      <div style="margin: 20px"><h2>使用 Vue 搭建檔案上傳 Demo</h2>        <h5><a href="http://kalacloud.com">卡拉雲</a> - 低程式碼開發工具,1 秒搭建上傳後臺</h5>        <a>使用卡拉雲無需懂任何前端技術,僅需拖拽即可搭建屬於你的後臺管理系統</a>
</div> <upload-files></upload-files> </div> </div></template><script>import UploadFiles from "./components/UploadFiles";export default { name: "App", components: { UploadFiles }};</script>

複製程式碼

給 Vue 上傳檔案服務配置訪問埠

檔案位置:src/vue.config.js

module.exports = {  devServer: {    port: 8081  }}

複製程式碼

執行 Vue 前端部分

到這裡,我們已經把 Vue 上傳檔案的前端部分寫完,執行起來看看效果吧。

在 kalacloud-vue-multiple-files-upload 根目錄跑一下:

npm run serve

複製程式碼

在瀏覽器開啟 http://localhost:8081/ 可以看到前端部分已經完美顯示。

檔案選擇器、上傳按鈕、檔案列表都已經可以顯示出來了,但還無法上傳。這是因為後端部分還沒有跑起來,接下來,我帶領大家手把手搭建上傳檔案的後端部分。

擴充套件閱讀:《 5 款最棒的 Vue UI 移動端元件庫 - 特別針對國內使用場景推薦

Vue 前端「上傳檔案」原始碼

你可以在我的 github 上下載到完整的 Vue 上傳檔案 Demo。

當然你也可以不用這麼費勁搭建前端做上傳檔案功能,直接使用卡拉雲,無需懂前後端,簡單拖拽即可生成一套屬於你自己的後臺管理工具。

✦ 後端部分 - 上傳檔案 Node.js + Express + Multer

前文我們介紹瞭如何使用 Vue 搭建上傳檔案管理工具的前端部分,接下來我教大家使用 Node.js + Express + Multer 來搭建一套上傳檔案的後端 Rest API,提供給 Vue 前端使用,從而實現 Vue 選擇檔案 + Axios 呼叫後端 API HTTP 通訊,最後把檔案上傳到伺服器指定目錄。

接下來,大家一起跟隨本教程建立一套 Node.js 上傳檔案 Rest API,它的功能包括:

  • 將 Vue 前端選中的檔案上傳到伺服器的靜態資料夾中

  • 限制上傳檔案大小,最大 2MB

  • GET 伺服器中儲存檔案的 URL ,可用於下載

  • GET 檔案資訊列表(檔名 + URL)

這是儲存所有上傳檔案的靜態資料夾:

如果我們 GET 檔案列表,Node.js Rest API 會返回:

GET /files ,API 返回 檔名 + URL

我們構建的 Node.js Rest API 包含這三個功能:

  • POST /upload 上傳一個檔案

  • GET /files 獲取檔案列表(檔名+URL)

  • GET /files/[filename] 下載指定檔案

擴充套件閱讀:《 頂級好用的 5 款 Vue table 表格元件測評與推薦

配置 Node.js 開發環境

在根目錄新建 Node.js 的後端資料夾 kalacloud-express-file-upload,接下來所有操作都在這個資料夾中進行。

mkdir kalacloud-express-file-uploadcd kalacloud-express-file-upload

複製程式碼

在 kalacloud-express-file-upload 資料夾根目錄安裝 Express、Multer、CORS 這三個模組:

npm install express multer cors

複製程式碼

package.json 檔案:

{  "name": "kalacloud-express-file-upload",  "version": "1.0.0",  "description": "Node.js Express Rest APis to Upload/Download Files",  "main": "server.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "keywords": [    "node js",    "upload",    "download",    "file",    "multipart",    "rest api",    "express"  ],  "author": "bezkoder",  "license": "ISC",  "dependencies": {    "cors": "^2.8.5",    "express": "^4.17.1",    "multer": "^1.4.2"  }}

複製程式碼

配置檔案上傳中介軟體 Multer

我們使用 Multer 中介軟體來處理多檔案上傳,更多 Multer 細節請閱讀它的 開發文件

檔案位置:src/middleware/upload.js

const util = require("util");const multer = require("multer");const maxSize = 2 * 1024 * 1024;let storage = multer.diskStorage({  destination: (req, file, cb) => {    cb(null, __basedir + "/resources/static/assets/uploads/");  },  filename: (req, file, cb) => {    console.log(file.originalname);    cb(null, file.originalname);  },});let uploadFile = multer({  storage: storage,  limits: { fileSize: maxSize },}).single("file");let uploadFileMiddleware = util.promisify(uploadFile);module.exports = uploadFileMiddleware;

複製程式碼

上面的程式碼我們做了這麼幾件事:

  • 匯入 multer 模組。

  • 配置 multer 為磁碟儲存引擎。

  • destination :指向用於儲存上傳檔案的資料夾。

  • filename :上傳檔案上傳後的檔名。

擴充套件閱讀:《 最好用的 7 款 Vue admin 後臺管理框架測評

使用 Multer 限制檔案大小

我們可以使用 Multer API 來限制上傳檔案大小,新增 limits: { fileSize: maxSize } 以限制檔案大小。

let storage = multer.diskStorage(...);const maxSize = 2 * 1024 * 1024;let uploadFile = multer({  storage: storage,  limits: { fileSize: maxSize }}).single("file");

複製程式碼

建立檔案上傳 / 下載控制器

在 controller 資料夾中建立 file.controller.js

上傳檔案:我們使用 upload() 函式

  • 使用中介軟體功能上傳檔案

  • 上傳檔案錯誤資訊(在 Multer 中介軟體函式中)

  • 返回資訊

下載檔案:

  • 使用 getListFiles() 讀取伺服器上傳資料夾中的所有檔案,包含檔名和 URL

  • 使用 download() 接收檔名作為輸入引數,然後使用 Express  res.downloa() 以附件形式傳輸 URL(目錄+檔名)

檔案位置:src/controller/file.controller.js

const uploadFile = require("../middleware/upload");const upload = async (req, res) => {  try {    await uploadFile(req, res);    if (req.file == undefined) {      return res.status(400).send({ message: "請選擇要上傳的檔案" });    }    res.status(200).send({      message: "檔案上傳成功: " + req.file.originalname,    });  } catch (err) {    res.status(500).send({      message: `無法上傳檔案: ${req.file.originalname}. ${err}`,    });  }};const getListFiles = (req, res) => {  const directoryPath = __basedir + "/resources/static/assets/uploads/";  fs.readdir(directoryPath, function (err, files) {    if (err) {      res.status(500).send({        message: "沒有找到檔案。",      });    }    let fileInfos = [];    files.forEach((file) => {      fileInfos.push({        name: file,        url: baseUrl + file,      });    });    res.status(200).send(fileInfos);  });};const download = (req, res) => {  const fileName = req.params.name;  const directoryPath = __basedir + "/resources/static/assets/uploads/";  res.download(directoryPath + fileName, fileName, (err) => {    if (err) {      res.status(500).send({        message: "無法獲取檔案。" + err,      });    }  });};module.exports = {  upload,  getListFiles,  download,};

複製程式碼

  • 我們首先呼叫中介軟體函式 uploadFile()

  • 如果 HTTP 請求不包含檔案,返回 400 錯誤資訊

  • 如果出現獲取錯誤,返回 500 錯誤資訊

如果使用者上傳檔案大小超限的檔案應該怎麼處理?

擴充套件閱讀:《 手把手教你Vue3+Node.js+Expres+MySQL環境搭建

使用 Multer 處理檔案大小超限錯誤

我們可以通過 catch() 來檢查檔案超限錯誤( LIMIT_FILE_SIZE

檔案位置:src/controller/file.controller.js

 const upload = async (req, res) => {  try {    await uploadFile(req, res);    ...  } catch (err) {    if (err.code == "LIMIT_FILE_SIZE") {      return res.status(500).send({        message: "檔案大小不能超過 2MB",      });    }    res.status(500).send({      message: `不能上傳檔案: ${req.file.originalname}. ${err}`,    });  }};

複製程式碼

設定後端 Rest API 上傳檔案的路徑

當 Vue 前端通過 Axios 傳送 HTTP 請求時,我們需要通過路由來確定伺服器應該如何響應

我們來設定三種常用到的上傳檔案所需功能

  • POST /uploadupload()

  • GET /filesgetListFiles()

  • GET /files/[fileName]download()

我們在 routes 資料夾中建立 index.js 檔案:

檔案位置:src/routes/index.js

const express = require("express");const router = express.Router();const controller = require("../controller/file.controller");let routes = (app) => {  router.post("/upload", controller.upload);  router.get("/files", controller.getListFiles);  router.get("/files/:name", controller.download);  app.use(router);};module.exports = routes;

複製程式碼

上面這段程式碼呼叫了我們前文寫的控制器 file.controller.js

擴充套件閱讀:《 最好的 5 款翻譯 API 介面對比測評

建立 Express 服務

最後一步,建立 Express 服務,在根目錄新建一個 server.js 檔案

檔案位置:kalacloud-express-file-upload/server.js

const cors = require("cors");const express = require("express");const app = express();global.__basedir = __dirname;var corsOptions = {  origin: "http://localhost:8081"};app.use(cors(corsOptions));const initRoutes = require("./src/routes");app.use(express.urlencoded({ extended: true }));initRoutes(app);let port = 8080;app.listen(port, () => {  console.log(`Running at localhost:${port}`);});

複製程式碼

匯入 express 和  cors 模組:

  • 建立 Express 應用,用於構建 Rest API,然後新增 cors 中介軟體。

  • 設定 http://localhost:8081 為 origin ,這裡允許前端傳入

擴充套件閱讀:《 如何使 Vue ECharts 柱狀圖中,每個柱子顏色各不同(隨機或指定顏色)

執行後端並測試

首先,在 kalacloud-express-file-upload 根目錄執行

node server.js

複製程式碼

把後端服務啟動起來。然後我們使用 Postman 來發送 HTTP 請求,看看後端是否執行正常。

➜  kalacloud-express-file-upload node server.jsRunning at localhost:8080

複製程式碼

接著我們使用 Postman 來測試一下,我們剛剛搭建的後端伺服器是否能正常執行

向後端伺服器發 POST 請求上傳檔案

上傳大於最大限制 (2MB) 的檔案,500 報錯。

GET 檢索檔案資訊列表:

我們可以使用返回的檔案 URL 下載這些檔案,例如: http://localhost:8080/files/kalacloud-logo.png

擴充套件閱讀:《 Video.js 使用教程 - 手把手教你基於 Vue 搭建 HTML 5 影片播放器

Vue + Node.js 上傳檔案前後端一起執行

在 kalacloud-vue-multiple-files-upload 資料夾根目錄執行前端 Vue

npm run serve

複製程式碼

在 kalacloud-express-file-upload 資料夾根目錄執行後端 Node.js

node server.js

複製程式碼

然後開啟瀏覽器輸入前端訪問網址:

到這裡整個前後端「上傳檔案」管理工具就搭建完成了。

Node.js 後端「上傳檔案」原始碼

你可以在我的 github 上下載到完整的 Node.js 後端「上傳檔案」原始碼。

如果你還沒搞懂,也不用著急,直接使用卡拉雲,無需懂任何前後端技術,僅需簡單的滑鼠拖拽即可快速生成包括「上傳檔案」管理在內的任何後臺管理工具。立即試用卡拉雲。

「上傳檔案」前後端搭建總結

本教程手把手教大家搭建 Vue 前端 + Node.js 後端 的「檔案上傳」管理工具,如果你一步步跟著走,一定已經把 Demo 跑起來了。但如果你會使用最新的低程式碼開發工具「卡拉雲」,完全不需要這麼繁瑣,僅需 1 分鐘,就能搭建起屬於自己的「檔案上傳」管理工具。

註冊開通卡拉雲,從側邊工具欄直接拖拽元件到頁面,生成上傳元件和檔案管理工具。1 分鐘搞定「檔案上傳」管理工具。

擴充套件閱讀: