Large file upload demo, the front end is based on Uppy, and the back end is based on koa

foreword

File upload basically all management systems and other projects have such a function. Because it is used Element, it is convenient to use the components
provided by it Upload, which is basically enough for ordinary uploading. But sometimes it involves the need to upload large files, and then you will face some problems: such as file upload timeout.

It is very troublesome to do it yourself, and there are so many things to consider. At this time, you can consider using a third-party packaged library. It is recommended here Uppy , mainly because this library has been maintained, and some libraries are a few years ago, for example WebUploader.

Just simple research, encounter problems, see official documents

Official documentation: https://uppy.io/docs/quick-start/

Official git: https://github.com/transloadit/uppy

Preparation

The front end is based on vue3, and the back end is based on koa. (The front end is the main business, the back end is a hobby, just a simple understanding)

front end

For details on project creation, see: Use Vite to build a Vue3 + Ts project , which will not be introduced here.

After building the project, you need to install: axios , element-plus, and run the project as shown below:

insert image description here

rear end

For details on project creation, see: Koa Learning 1: Initializing Projects

After running the project, as shown below:
insert image description here

to integrate

Let's deal with it now, so that the vue front end can request data

The backend
needs to be installed koa2-corsto solve cross-domain problems

npm install koa2-cors

after editedmain.js

// 导入Koa
const Koa = require("koa");
// 用于解决跨域
const cors = require("koa2-cors");
// 实例化
const app = new Koa();

app.use(cors());

// 中间件
app.use(async (ctx, next) => {
    
    
  const start = Date.now();
  await next();
  ctx.body = "hellow koa";
});

// 监听端口
app.listen(5000, () => {
    
    
  console.log(`app listening at http://localhost:5000`);
});

front end

Modify vite.config.tsthe configuration file

import {
    
     defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
    
    
    plugins: [vue()],
    server: {
    
    
        proxy: {
    
    
            '/api': {
    
    
                target: 'http://localhost:5000/',
                changeOrigin: true,
                rewrite: path => path.replace(/^\/api/, '')
            }
        }
    }
});

ReviseApp.vue

<template>
  <div class="upload-container">
    <el-button type="primary" ="getData">上传</el-button>
    <p>数据是:{
    
    {
    
     message }}</p>
  </div>
</template>

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

const message = ref('');

// 请求数据
const getData = () => {
    
    
  axios.get('http://localhost:5000/')
    .then(res => {
    
    
      message.value = res.data
      console.log("数据是:", res.data)
    })
}

</script>

<style scoped>
.upload-container {
    
    
  display: flex;
  justify-content: center;
  align-items: center;
  height: 700px;
}
</style>

renderings
insert image description here

Simple demo, upload pictures

front end

install uppy

npm install /core /drag-drop /status-bar /xhr-upload
  • core core package
  • drag-dropUsed to implement drag and drop upload
  • status-barShow upload progress bar
  • xhr-uploadImplement file upload
<template>
  <div class="upload-container">
    <div id="drag-drop-area">
      <!-- 默认样式,也可以在里面进行自定义 -->
    </div>
    <div id="status-bar"></div>
  </div>
</template>

<script setup lang="ts">
import {
    
     ref, onMounted } from "vue"
import {
    
     ElMessage } from 'element-plus'

import Uppy from '@uppy/core';
import DragDrop from '@uppy/drag-drop';
import StatusBar from '@uppy/status-bar';
import XHRUpload from '@uppy/xhr-upload';

//引入样式
import '@uppy/core/dist/style.min.css';
import '@uppy/drag-drop/dist/style.min.css';

// 1mb大小
const ONE_MB = 1024 * 1024;

const uppy = ref()

onMounted(() => {
    
    
  uppy.value = new Uppy({
    
    
    debug: true,  // 允许拖拽
    autoProceed: false, // 是否自动上传
    restrictions: {
    
    
      maxFileSize: 10 * ONE_MB, // 设置最大文件大小
      maxNumberOfFiles: 5, // 设置最大上传文件数量
      allowedFileTypes: ['.jpg', '.jpeg', '.png'] // 设置允许的文件类型
    }
  })
    .use(DragDrop, {
    
     target: '#drag-drop-area', note: '拖放或点击' }) // 启用拖动
    .use(StatusBar, {
    
     target: '#status-bar' })   //启用进度条
    .use(XHRUpload, {
    
    
      endpoint: 'http://localhost:5000/upload', // 设置上传文件的API接口
      formData: true // 启用FormData发送数据
    });

  // 监听文件上传
  uppy.value.on('upload-success', (file: any, response: any) => {
    
    
    // console.log("上传的文件:", file)
    console.log("返回的信息:", response)
    if (response.body.code == 0) {
    
    
      ElMessage.success(`文件${
    
    file.name}上传成功`)
    } else {
    
    
      ElMessage.error(`文件${
    
    file.name}上传失败,${
    
    response.body.message}`)
    }
  })
})


</script>

<style scoped>
.upload-container {
    
    
  display: flex;
  justify-content: center;
  align-items: center;
  height: 700px;
}
</style>

rear end

Install koa-bodymiddleware, which can conveniently handle file data in the request body.

npm install koa-body

Install koa-routermiddleware for postrequests

npm install koa-router

Revisemain.js

// 导入Koa
const Koa = require("koa");
// 用于解决跨域
const cors = require("koa2-cors");
// 用于文件上传
const {
    
     koaBody } = require("koa-body");
// 用于处理路径
const path = require("path");
// 引入路由
const Router = require("koa-router");

// 注意如果有改动,则要重启一下。如果觉得麻烦可以设置热重启,具体见:https://blog.csdn.net/weixin_41897680/article/details/130907232

// 实例化
const app = new Koa();
const router = new Router();

app.use(cors());

// 配置文件上传
app.use(
  koaBody({
    
    
    multipart: true, // 允许多文件
    formidable: {
    
    
      uploadDir: path.join(__dirname, "uploads"), // 设置文件上传目录,必须有这个文件夹不然会报错
      keepExtensions: true, // 保持文件扩展名
    },
  })
);

router.get("/", async (ctx) => {
    
    
  ctx.body = "hello Koa";
});

// 文件上传
router.post("/upload", async (ctx) => {
    
    
  // 获取上传的文件
  try {
    
    
    const file = await ctx.request.files.file;
    console.log("文件信息:", file);
    ctx.body = {
    
    
      message: "文件上传成功",
      data: {
    
    
        size: file.size, //文件大小
        fileName: file.originalFilename, // 文件的原始名称
        filePath: file.filepath, // 在服务器上的保存路径
        updateTime: file.lastModifiedDate, // 上次修改的时间
      },
    };
  } catch (err) {
    
    
    ctx.body = {
    
    
      message: err,
      data: {
    
    },
    };
  }
});

//挂载路由
app.use(router.routes()).use(router.allowedMethods());

// 监听端口
app.listen(5000, () => {
    
    
  console.log(`app listening at http://localhost:5000`);
});

insert image description here
insert image description here

Large file upload, resumable upload

To implement multipart uploads and support resuming uploads from breakpoints needs to be based onTus

Tus is an open protocol for resumable uploads built on top of HTTP. This means accidentally closing a tab or losing your connection, allowing you to continue, for instance, your 10GB upload instead of starting over.

Tus supports any language, any platform, and any network. It requires a client and server integration to work. You can check out the client and server implementations to find a server for your preferred language.

front end

The front end has not changed much, and Uppythe corresponding plug-in is provided for us. The modified code is as follows:

<!--  大文件上传 -->
<template>
  <div class="upload-container">
    <div id="drag-drop-area">
      <!-- 默认样式,也可以在里面进行自定义 -->
    </div>
    <div id="status-bar"></div>
    <br />
    <el-button type="primary" ="pauseOrResume">{
    
    {
    
     isUploadding ? '暂停' : '开始' }}</el-button>
  </div>
</template>

<script setup lang="ts">
import {
    
     ref, onMounted } from "vue"
import {
    
     ElMessage } from 'element-plus'

import Uppy from '@uppy/core';
import DragDrop from '@uppy/drag-drop';
import StatusBar from '@uppy/status-bar';
import Tus from '@uppy/tus';

//引入样式
import '@uppy/core/dist/style.min.css';
import '@uppy/drag-drop/dist/style.min.css';

// 1mb大小
const ONE_MB = 1024 * 1024;
// 是否正在上传,默认在上传
const isUploadding = ref(true)


let uppy: Uppy;

onMounted(() => {
    
    
  uppy = new Uppy({
    
    
    debug: true,  // 允许拖拽
    autoProceed: false, // 是否自动上传
    restrictions: {
    
    
      maxFileSize: 300 * ONE_MB, // 设置最大文件大小
      maxNumberOfFiles: 5, // 设置最大上传文件数量
      allowedFileTypes: ['.jpg', '.jpeg', '.png', '.zip'] // 设置允许的文件类型
    },
  })
    .use(DragDrop, {
    
     target: '#drag-drop-area', note: '拖放或点击' }) // 启用拖动
    .use(StatusBar, {
    
     target: '#status-bar' })   //启用进度条
    .use(Tus, {
    
    
      endpoint: 'http://127.0.0.1:5000/files', // 设置上传文件的API接口
      limit: 5, // 限制同时进行的上传数量,默认值20,不要没有限制或者过大
      chunkSize: 5 * ONE_MB // 设置分片的大小
    });

  // 监听文件上传
  uppy.on('complete', (result: any) => {
    
    
    // result是一个对象,属性是:
    // 会返回failed(Array),因为可以多文件上传会返回一个数组
    // successful(Array),因为可以多文件上传会返回一个数组,包含文件上传成功的信息
    console.log("上传完成:",result)
    if (Array.isArray(result.failed) && result.failed.length>0) {
    
    
      ElMessage.error(`文件上传失败,${
    
    result.failed}`)
    } else {
    
    
      ElMessage.success(`文件上传成功`)
    }

  })
})

// 暂停与恢复
const pauseOrResume = () => {
    
    
  if (isUploadding.value) {
    
    
    // 正在上传
    uppy.pauseAll()
  } else {
    
    
    // 暂停中
    uppy.resumeAll()
  }
  isUploadding.value = !isUploadding.value
}


</script>

<style scoped>
.upload-container {
    
    
  width: 300px;
  margin: 100px auto;
  height: 700px;
}
</style>

rear end

The backend has changed a lot. You need to make your server support it Tus. It just so happens that the official provides corresponding plug-ins (Java backend and php backend can be integrated by Baidu)

Plugin official documentation
https://github.com/tus/tus-node-server

The official integration case, this is very important, will introduce the properties and events of the plug-in
https://github.com/tus/tus-node-server/tree/main/packages/server

Install

npm i /file-store /server tus-node-server

the code

const Koa = require("koa");
const {
    
     Server } = require("@tus/server");
const {
    
     FileStore } = require("@tus/file-store");
// 用于解决跨域
const cors = require("koa2-cors");

const host = "127.0.0.1";
const port = 5000;
// 创建一个tusServer服务
const tusServer = new Server({
    
    
  path: "/files", // 路由
  datastore: new FileStore({
    
     directory: "./files" }), // 文件存储的位置
});

const app = new Koa();

app.use(cors());

// 将 tus-server 添加为 Koa 的中间件
app.use(async (ctx, next) => {
    
    
  // 注:tus-server 的处理程序要求精确匹配路由路径,这里无法使用koa-router。只能当作一个单独的中间件使用
  await tusServer.handle.bind(tusServer)(ctx.req, ctx.res);
});

// 注:tus-server 的处理程序要求精确匹配路由路径,这里无法使用koa-router。只能当作一个单独的中间件使用

app.listen(port, host, () => {
    
    
  console.log(`Server is running on http://${
    
    host}:${
    
    port}`);
});

Execution effect

insert image description here
After the upload is complete, two files will be generated, as follows:
the first is the uploaded file, which will become a binary file,
and the second is the information about the file .
insert image description here
The front-end Uppylibrary will also return the file information, as shown in the figure below:

insert image description here

the code

The code is put on the code cloud, if you are interested, you can take a look for yourself

front end

Address
https://gitee.com/idonotyou/vue-upload

run

npm i 
npm run dev

rear end

Address
https://gitee.com/idonotyou/koa-upload

run

npm i 
npm run dev

Guess you like

Origin blog.csdn.net/weixin_41897680/article/details/132617289