minio分片上传

This commit is contained in:
none 2023-03-06 18:22:04 +08:00
parent 6649aa8cfa
commit 709027df50
3 changed files with 112 additions and 45 deletions

View File

@ -7,8 +7,26 @@ export function image(categoryId: number, file: File) {
});
}
export function minioToken(extension: string) {
return client.get("/backend/v1/upload/minio-token", {
export function minioUploadId(extension: string) {
return client.get("/backend/v1/upload/minio-upload-id", {
extension,
});
}
export function minioPreSignUrl(
uploadId: string,
filename: string,
partNumber: number
) {
return client.get("/backend/v1/upload/minio-pre-sign-url", {
upload_id: uploadId,
filename,
part_number: partNumber,
});
}
export function minioMerge(filename: string, uploadId: string) {
return client.get("/backend/v1/upload/minio-merge", {
filename,
upload_id: uploadId,
});
}

View File

@ -12,8 +12,8 @@ import {
import Dragger from "antd/es/upload/Dragger";
import { useEffect, useState } from "react";
import { generateUUID, getToken } from "../../utils";
import { minioToken } from "../../api/upload";
import Resumable from "resumablejs";
import { minioUploadId } from "../../api/upload";
import { UploadChunk } from "../../js/minio-upload-chunk";
interface PropsInterface {
categoryId: number;
@ -29,30 +29,24 @@ interface FileItem {
file: File;
resource_type: string;
loading: boolean;
R: Resumable | undefined;
run: UploadChunk;
}
export const UploadVideoButton = (props: PropsInterface) => {
const [showModal, setShowModal] = useState(false);
const [fileList, setFileList] = useState<FileItem[]>([]);
const getMinioConfig = async () => {
let resp: any = await minioToken("mp4");
const getMinioUploadId = async () => {
let resp: any = await minioUploadId("mp4");
return resp.data;
};
const r = new Resumable({
chunkSize: 1 * 1024 * 1024,
fileParameterName: "file",
uploadMethod: "POST",
});
const uploadProps = {
multiple: true,
beforeUpload: async (file: File) => {
if (file.type === "video/mp4") {
//添加到本地待上传
let data = await getMinioConfig();
let data = await getMinioUploadId();
let item: FileItem = {
id: generateUUID(),
duration: 0,
@ -62,38 +56,13 @@ export const UploadVideoButton = (props: PropsInterface) => {
file: file,
resource_type: data["resource_type"],
loading: true,
R: undefined,
run: new UploadChunk(
file,
data["upload_id"],
data["filename"]
),
};
// 初始化上传对象
let r = new Resumable({
target: data["url"],
chunkSize: 6 * 1024 * 1024,
simultaneousUploads: 1,
uploadMethod: "PUT",
method: "octet",
testChunks: false, //不校验已上传的chunks
chunkNumberParameterName: "partNumber",
query: {
uploadId: item.id,
},
});
r.on("fileProgress", (file: Resumable.ResumableFile) => {
item.progress = file.progress(false) * 100;
console.log("进度", item.progress);
});
r.on("error", (e) => {
console.log("错误", e);
});
r.addFile(item.file);
item.R = r;
setTimeout(() => {
if (item.R) {
item.R.upload();
}
}, 500);
item.run.start();
setFileList([item, ...fileList]);
} else {
message.error(`${file.name} 并不是 mp4 视频文件`);

View File

@ -0,0 +1,80 @@
import axios, { Axios } from "axios";
import { minioMerge, minioPreSignUrl } from "../api/upload";
export class UploadChunk {
client: Axios;
file: File;
progress: number;
chunkNumber: number;
isStop: boolean;
chunkSize: number;
chunkIndex: number;
uploadId: string;
filename: string;
onError: ((err: string) => void | undefined) | undefined;
onSuccess: (() => void | undefined) | undefined;
onProgress: ((progress: number) => void) | undefined;
constructor(file: File, uploadId: string, filename: string) {
this.client = axios.create({
timeout: 15000,
withCredentials: false,
});
this.file = file;
this.progress = 0;
this.isStop = false;
this.chunkIndex = 1;
this.chunkSize = 6 * 1024 * 1024;
this.chunkNumber = Math.ceil(file.size / this.chunkSize);
this.uploadId = uploadId;
this.filename = filename;
}
start() {
if (this.isStop) {
return;
}
let start = (this.chunkIndex - 1) * this.chunkSize;
if (start > this.file.size) {
//上传完成
minioMerge(this.filename, this.uploadId)
.then((res) => {
console.log("合并成功", res);
})
.catch((e) => {
console.error("合并失败", e);
});
return;
}
const chunkData = this.file.slice(start, start + this.chunkSize);
const boolname = this.file.name + "-" + this.chunkIndex;
const tmpFile = new File([chunkData], boolname);
minioPreSignUrl(this.uploadId, this.filename, this.chunkIndex)
.then((res: any) => {
return this.client.put(res.data.url, tmpFile, {
headers: {
"Content-Type": "multipart/form-data",
},
});
})
.then(() => {
this.chunkIndex += 1;
this.start();
})
.catch((e) => {
console.error("获取签名url失败", e);
});
}
stop() {
this.isStop = true;
}
resume() {
this.isStop = false;
this.start();
}
}