1、docker部署minio、tusd服务
1.1 新建docker-compose.yml
minio API: http://ip:9100
minio控制台: http://ip:9101
tus API: http://ip:9102/files/
tus webhooh: http:172.0.0.1:3000/files/webhooh(用户鉴权API)
version: '3.7'
services:
minio:
image: minio/minio:RELEASE.2023-07-07T07-13-57Z
container_name: minio-server
restart: always
hostname: minio
ports:
# API服务端口
- 9100:9000
# 管理系统端口
- 9101:9001
environment:
# 管理系统用户名
MINIO_ROOT_USER: admin
# 管理系统密码
MINIO_ROOT_PASSWORD: admin123
volumes:
- ./data:/data
- ./config:/root/.minio/
command: minio server --console-address ':9001' /data
privileged: true
networks:
- file-server
tus-server:
image: tusproject/tusd:2.0.0.rc21
container_name: tus-server
ports:
- 9102:1080
environment:
# minio凭证,可以在minio管理系统生成key
AWS_ACCESS_KEY_ID: admin
AWS_SECRET_ACCESS_KEY: admin123
AWS_REGION: eu-west-1
# 配置minio地址、jwt鉴权地址,转发headers字段
command: -s3-bucket file-oos -s3-endpoint http://minio:9000 -hooks-http http:172.0.0.1:3000/files/webhooh -hooks-http-forward-headers Authorization -hooks-http-retry 3 -verbose
privileged: true
networks:
- file-server
networks:
file-server:
driver: bridge
ipam:
config:
- subnet: 155.119.0.0/16
gateway: 155.119.0.1
1.2 启动服务
docker-compose up -d
2、编写鉴权接口,简单点的话就校验jwt token
import { Controller, Post, Req} from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
@ApiTags('文件管理')
@Controller('files')
export class AuthController {
@ApiOperation({ summary: 'tus服务鉴权' })
@Post('webhooh')
webhooh(@Req() request: Request) {
/**
* tus服务提供的钩子
* pre-create: 上传请求创建前
* post-create: 创建上传请求
* post-receive: 接收数据
* post-finish: 上传结束,可以在这里更改文件名
*/
const body: any = request.body;
if (body.Type === 'post-finish') {
const uploadData = body.Event.Upload;
// 文件名和类型
const { filename, filetype } = uploadData.MetaData;
// minio桶名
const bucket = uploadData.Storage.Bucket
}
return '鉴权通过';
}
}
3、vue使用uppy上传文件(支持多文件、断点续传、秒传等)
<!-- 大文件上传 -->
<template>
<div class="upload-container">
<div id="uppy-dashboard"></div>
<!-- <div id="uppy-drag-drop"></div> -->
<!-- <div id="uppy-progress-bar"></div> -->
<!-- <div id="uppy-status-bar"></div> -->
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { locale } from './locale'
import Uppy from '@uppy/core'
// import DragDrop from '@uppy/drag-drop'
// import StatusBar from '@uppy/status-bar'
import Tus from '@uppy/tus'
import Dashboard from '@uppy/dashboard'
// import ProgressBar from '@uppy/progress-bar'
//引入样式
import '@uppy/core/dist/style.min.css'
import '@uppy/dashboard/dist/style.min.css'
import '@uppy/drag-drop/dist/style.min.css'
import '@uppy/progress-bar/dist/style.min.css'
// 1mb大小
const ONE_MB = 1024 * 1024
let uppy: Uppy
onMounted(() => {
uppy = new Uppy({
debug: true, // 允许拖拽
autoProceed: false, // 是否自动上传
restrictions: {
maxFileSize: 500 * ONE_MB, // 设置最大文件大小
maxNumberOfFiles: 5, // 设置最大上传文件数量
allowedFileTypes: ['.jpg', '.jpeg', '.png', '.zip', '.webm'], // 设置允许的文件类型
},
})
.use(Dashboard, {
inline: true,
target: '#uppy-dashboard',
locale,
waitForThumbnailsBeforeUpload: true, // 等待上传之前的缩略图
showProgressDetails: true, // false: 百分比;true:百分比 + 剩余时间
// note: '文件上传', // 底部文案
proudlyDisplayPoweredByUppy: false, // 隐藏底部的uppy文案
})
// .use(ProgressBar, { target: '#uppy-progress-bar' })
// .use(DragDrop, { target: '#uppy-drag-drop', note: '拖放或点击' }) // 启用拖动
// .use(StatusBar, { target: '#uppy-status-bar' }) //启用进度条
.use(Tus, {
endpoint: 'http://127.0.0.1:9102/files/', // 设置上传文件的API接口
limit: 5, // 限制同时进行的上传数量,默认值20,不要没有限制或者过大
chunkSize: 500 * ONE_MB, // 设置分片的大小
allowedMetaFields: ['name', 'type'], // 上传所有元数据
async onBeforeRequest(req, file) {
console.log(file)
// 添加jwt token
const token = localStorage.getItem('test-token') as string
req.setHeader('Authorization', token)
},
})
uppy.on('files-added', (result: any) => {
console.log('文件批量添加完成', result)
})
// 监听文件上传
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(`文件上传成功`)
}
})
})
</script>