大文件分片上传前后端实现

1.前端代码

<template>
  <div class="upload_container">
    <el-progress :percentage="progressNum" />
    <input type="file" ref="file" @change="selectFile" />
    <el-button type="primary" @click="uploadFile">上传文件</el-button>
  </div>
</template>

<script setup lang="ts">
import axios from "axios";
import { reactive, ref } from "vue";
import { ElMessage } from "element-plus";

const file = ref(null); //
const selectFileobj = ref(null); //用来保存选择的文件
const progressNum = ref(0); //进度条
const chunk_size = ref(10 * 1024 * 1024); //分片大小为10M
const uploadSize = ref(0); //已上传的文件大小

//选择文件
const selectFile = () => {
  console.log(file.value?.files); //获取到文件对象
  if (file.value?.files[0]) {
    selectFileobj.value = file.value?.files[0];
  }
};

//上传文件
const uploadFile = async () => {
  if (selectFileobj.value) {
    console.log("selectFileobj: ", selectFileobj.value);
    const { name, size, type } = selectFileobj.value;

    while (uploadSize.value < size) {
     
      //已上传的文件大小小于时
      const fileChunk = selectFileobj.value?.slice(
        uploadSize.value,
        uploadSize.value + chunk_size.value
      );
      console.log("fileChunk: ", fileChunk); //得到每次切片好的文件

      const fd = new FormData();
      fd.append("name", name);
      fd.append("type", type);
      fd.append("size", size);
      fd.append("uploadSize", uploadSize.value);
      fd.append("file", fileChunk);

      const res = await axios.post("http://localhost:8000/upload_file", fd);
      console.log("res:上传文件 ", res);
      uploadSize.value += fileChunk.size;
      progressNum.value = (uploadSize.value / size).toFixed(2) * 100   //进度条控制
    }
  } else {
    ElMessage({
      message: "请选择文件",
      type: "warning",
    });
  }
};
</script>

<style scoped>
.upload_container {
  width: 200px;
  text-align: left;
}
</style>

2.后端node.js

var express = require("express");
const bodyParser = require("body-parser");
const uploader = require("express-fileupload"); //express-fileupload插件
const { extname, resolve } = require("path");
const { existsSync, appendFileSync, writeFileSync } = require("fs"); //文件读写

// 实例化express
var app = express();

//配置bodyparser 解析的作用  固定写法
app.use(bodyParser.json()); //解析json
app.use(bodyParser.urlencoded()); //解析表单数据
app.use(uploader()); //此中间件是为了拿到前端传的文件类型的数据
app.use("/", express.static("file"));

//跨越处理
app.all("*", (req, res, next) => {
  res.header("Access-Control-Allow-origin", "*");
  res.header("Access-Control-Allow-Methods", "POST,GET");
  next();
});

app.post("/upload_file", (req, res) => {
  // console.log("req: ", req);
  // 获取前端上传的参数
  const { name, type, size, uploadSize } = req.body;
  const { file } = req.files; //文件

  const filePath = resolve(__dirname, "./file/" + name); //拼接路径
  if (uploadSize !== "0") {
    if (!existsSync(filePath)) {
      res.send({
        code: 400,
        message: "no file exists",
      });
      return;
    }

    //写文件
    appendFileSync(filePath, file.data);
    res.send({
      code: 200,
      message: "padding",
      data: {
        videoUrl: "http://localhost:8000/" + name,   //将url返回给前端展示
      },
    });
  } else {
    writeFileSync(filePath, file.data); //创建并开始写文件
    res.send({
      code: 200,
      message: "file is created",
    });
  }
});

app.listen(8000, function () {
  console.log("服务已启动,端口8000");
});

posted @ 2023-05-08 14:56  顺·  阅读(119)  评论(0编辑  收藏  举报