首先说的是oss分片上传
要用oss分片上传首先要new一个oss对象,那项目里面先装上oss依赖具体怎么装我就不在写了,装好之后具体要new看代码
const res = await POST_ALIOSS_GETSTS() //请求拿到oss相关的权限什么的下面好用
ossInfo = res
client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: `oss-${ossInfo.region}`,
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: ossInfo.credentials.access_key_id,
accessKeySecret: ossInfo.credentials.access_key_secret,
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: ossInfo.credentials.security_token,
// 填写Bucket名称,例如examplebucket。
bucket: ossInfo.bucket,
});
然后选择文件去上传
// 选择文件
const changeFile = (uploadFile: UploadFile) => {
isUploadSuccessful.value = true
percentageUpload.value = 0
isUpload.value = true
fileList.value = []
fileList.value.push(uploadFile)
// formData.value.zip_path = ''
const fileFormData = new FormData()
fileFormData.append("file", uploadFile.raw as Blob)
const data = uploadFile.raw as Blob;
const name = getbaseurl(data)
formData.value.zip_path = name
// const url = ossInfo.endpoint + '/' + name
if (userInfo.oss_type == 'ali') {
ossFragment(data, name)
} else {
// minio分片上传
fileSharding(data, name, uploadRef.value)
}
}
下面开始上传
const headers = {
// 指定该Object被下载时的网页缓存行为。
// "Cache-Control": "no-cache",
// 指定该Object被下载时的名称。
// "Content-Disposition": "example.txt",
// 指定该Object被下载时的内容编码格式。
// "Content-Encoding": "utf-8",
// 指定过期时间,单位为毫秒。
Expires: '43200000',
// 指定Object的存储类型。
// "x-oss-storage-class": "Standard",
// 指定Object标签,可同时设置多个标签。
// "x-oss-tagging": "Tag1=1&Tag2=2",
// 指定初始化分片上传时是否覆盖同名Object。此处设置为true,表示禁止覆盖同名Object。
// "x-oss-forbid-overwrite": "true",
};
// oss分片上传
const ossFragment = async (data, name) => {
const options = {
// 获取分片上传进度、断点和返回值。
progress: (p, cpt, res) => {
if (cpt) {
abortCheckpoint = cpt
console.log(res)
}
percentageUpload.value = Number((p * 100).toFixed(0))
console.log(percentageUpload.value)
if (percentageUpload.value == 100) {
isUpload.value = false
}
// console.log("JD", Number((p * 100).toFixed(0)));
},
fileSize: data.size, // 文件大小
// 设置并发上传的分片数量。
parallel: 3,
// 设置分片大小。默认值为1 MB,最小值为100 KB。
partSize: 1024 * 1024 * 6,
timeout: 43200000,//设置超时时间
// uploadId: uploadId,
headers,
// 自定义元数据,通过HeadObject接口可以获取Object的元数据。
// meta: { year: 2020, people: "test" },
// mime: "text/plain",
};
try {
// 分片上传。
const res = await client.multipartUpload(name, data, {
...options,
});
console.log("---", res);
} catch (err) {
console.log("12121", err);
isUploadSuccessful.value = false
}
}
// 取消上传
const cancelUpload = () => {
if (userInfo.oss_type == 'ali') {
removeFile()
isUpload.value = false
client.abortMultipartUpload(
abortCheckpoint.name,
abortCheckpoint.uploadId
);
} else {
cancelUploadMinio()
// source.value.cancel('取消上传')
}
// 中断分片上传。
removeFile()
isUpload.value = false
}
里面有具体的取消上传获取上传进度的方法,还有上传过程中设置单片上传的过期时间,oss权限的时间过期时间需要在接口里面过去信息的时候去设置,具体应该是在服务端设置的
minio的分片上传
minio前端分片上传其实和oss差不多首先也要new一个minio对象
const getOssSigns = async () => {
const res = await getOssSign()
ossInfo = res
if (res) {
// console.log(res)
createMinio({
endPoint: res.endpoint,
accessKey: res.access_key,
secretKey: res.signature,
port: res.policy,
useSSL: false,
sessionToken: res.security_token
})
return res
}
}
const createMinio = (config: {
endPoint: string
accessKey: string
secretKey: string
port: string
useSSL: boolean
sessionToken: string
}) => {
if (!config) throw new Error('minio配置信息错误')
minioClient = new Minio.Minio.Client(config)
// this.minioClient = minioClient
}
//上传操作 当你看到这一行的时候赶紧跑路这活干不下去 没法待
let index = 0;//上传顺序
let SuccessfulIndex = 0; //传成功顺序
// let tryTimes = 0; //重试次数最多三次
// let fileShardinglist = []
const chunkSize = 100 * 1024 * 1024; // 切片大小为5M
let sourceList: any = [] //上传成的CopySourceOptions链接数组
let objectsList: any = []//上传成功的链接
let dateTime: any = ''//当前时间戳
let minioClient: any = null //minio对象
let chunks//总的数量
let fileComponentEnd//图层库合并字段
let source: any = []//取消请求token
let sourceFolder //分片目标文件夹
const percentageUpload = ref<any>(0)
const isUploadSuccessful = ref<any>(true)
const isUpload = ref(false) // 上传弹窗的是否展示
const uploadRefs = ref<any>()
// 文件分片计算
const fileSharding = async (file, nameUrl, uploadRef) => {
uploadRefs.value = uploadRef
chunks = Math.ceil(file.size / chunkSize);
dateTime = new Date().getTime()
SuccessfulIndex = 0
index = 0
sourceList = []
objectsList = []
source = []
percentageUpload.value = 0
const res = await getOssSigns()
if (res) {
concurrence(file, nameUrl)
}
}
// 并发请求
const concurrence = (file, nameUrl) => {
let num: any = 3
source = []
if ((chunks - index) < 3) {
num = chunks - index
} else {
num = 3
}
// console.log(index, num);
for (let i = 0; i < num; i++) {
index++
// console.log(index, i, num);
minioUploadApi(file, nameUrl, index)
}
}
// 上传分片
const minioUploadApi = async (file, nameUrl, num) => {
const slice = file.slice((num - 1) * chunkSize, num * chunkSize);
const fileName = 'modelBasefragment/' + dateTime + '/'; // 文件名字
sourceFolder = fileName
const UploadFileFun = new UploadFile({
...ossInfo,
fileData: slice,
filePath: fileName,
fileName: (num - 1),
fileType: file.type
})
UploadFileFun.start()
.then((res) => {
// console.log('+++', res)
if (res.status === 200) {
SuccessfulIndex++
// console.log('+++', slice, url, index, file.type)
const data = new Minio.Minio.CopySourceOptions({
Bucket: ossInfo.bucket,
Object: fileName + (SuccessfulIndex - 1),
})
sourceList.push(data)
objectsList.push(fileName + (SuccessfulIndex - 1))
percentageUpload.value = Math.round((100 * SuccessfulIndex) / chunks)
// console.log('+++', progress, data)
// console.log(SuccessfulIndex, chunks);
if (SuccessfulIndex < chunks) {
// console.log(SuccessfulIndex, chunks);
if (SuccessfulIndex % 3 == 0) {
// console.log(SuccessfulIndex % 3);
concurrence(file, nameUrl)
}
} else if (SuccessfulIndex == chunks) {
// composePromise(nameUrl)
composePromise(fileName, nameUrl)
}
// 成功回调
} else {
// 失败回调
console.log('上传失败!')
isUploadSuccessful.value = false
}
})
.catch((error) => {
console.log('上传失败!', error)
isUploadSuccessful.value = false
})
source.push(UploadFileFun.setCancelToken())
}
// 合并分片
const composePromise = async (composeUrl, nameUrl) => {
console.log(composeUrl, nameUrl);
const res = await GET_ALIOSS_COMPONENT({ isDelete: true, sourceFolder: composeUrl, target: nameUrl })
console.log(res)
if (res) {
console.log('开始合并!')
} else {
isUpload.value = false
uploadRefs.value?.clearFiles()
}
}
// // 合并分片
// const composePromise = (nameUrl) => {
// const destOption = new Minio.Minio.CopyDestinationOptions({
// Bucket: ossInfo.bucket,
// Object: nameUrl,
// })
// console.log(destOption, sourceList)
// const composePromise = minioClient.composeObject(destOption, sourceList)
// composePromise
// .then((result) => {
// console.log('Success...', result)
// isUpload.value = false
// removerobj()
// })
// .catch((e) => {
// console.log('error', e)
// })
// }
//删除分片
const removerobj = () => {
console.log(objectsList);
// if (objectsList.length > 0) {
minioClient.removeObjects(ossInfo.bucket, objectsList, function (e) {
if (e) {
return console.log(e)
}
console.log('Success')
})
// }
}
//取消上传
const cancelUploadMinio = () => {
if (source.length > 0 && isUpload.value) {
source.forEach(res => {
res.cancel('取消上传')
})
removerobj()
uploadRefs.value?.clearFiles()
}
}
上面其中用到的minio的封装上传在下面
const Minio = window['minio-js']
const userStore = useUserStore()
// 获取上传通信证
export async function getOssSign() {
let oss_type = 'ali'
const userInfo = userStore.$state.userInfo
oss_type = userInfo.oss_type || 'ali'
if (oss_type === 'ali') {
const res = await POST_ALIOSS_GETSIGNATURE()
return res
} else {
const res = await POST_ALIOSS_GETSTS()
if (res) {
const {
bucket,
endpoint,
credentials: { access_key_id, access_key_secret, security_token }
} = res
const ipStartIdx = endpoint.indexOf('//')
const ipEndIdx = endpoint.lastIndexOf(':')
const ips = endpoint.substring(ipStartIdx + 2, ipEndIdx)
const por = endpoint.substring(ipEndIdx + 1)
return {
bucket,
endpoint: ips,
policy: Number(por) || 80,
access_key: access_key_id,
signature: access_key_secret,
security_token
}
}
}
}
export class UploadFile {
fileData: File
filePath: string
fileName: string
fileType: string
access_key: string
signature: string
policy: string
bucket: string
endpoint: string
security_token: string
hostUrl: string
formData: FormData | null
minioClient: Minio.Minio.Client | null
fileBuffer: Buffer | null
cancelToken: CancelTokenSource | null
axiosMethod: string
oss_type: string
constructor(params: {
fileData: File
filePath: string
fileName: string
fileType?: string
access_key: string
signature: string
policy: string
bucket?: string
endpoint?: string
security_token: string
}) {
const {
fileData,
filePath,
fileName,
fileType = 'multipart/form-data',
access_key,
signature,
policy,
bucket = '',
endpoint = '',
security_token
} = params
this.fileData = fileData
this.filePath = filePath
this.fileName = fileName
this.fileType = fileType
this.hostUrl = ''
this.access_key = access_key
this.policy = policy
this.signature = signature
this.formData = null
this.minioClient = null
this.fileBuffer = null
this.cancelToken = null
this.axiosMethod = 'post'
this.oss_type = 'ali'
this.bucket = bucket || ''
this.endpoint = endpoint || ''
this.security_token = security_token
this.init()
}
//------------------------------------------------初始化
init() {
const userInfo = userStore.$state.userInfo
this.oss_type = userStore.$state.userInfo.oss_type || 'ali'
this.hostUrl = userStore.$state.userInfo.oss_url
const cancelToken = axios.CancelToken.source()
this.cancelToken = cancelToken
if (userInfo.oss_type === 'minio') {
this.axiosMethod = 'put'
this.createMinio({
endPoint: this.endpoint,
accessKey: this.access_key,
secretKey: this.signature,
port: this.policy,
useSSL: false,
sessionToken: this.security_token
})
} else {
this.axiosMethod = 'post'
}
}
/*******
* @description: 开始上传
* @param {*} progressCallback 上传进度callback
* @return {*}
*/
start(progressCallback: ((progressEvent: ProgressEvent) => void) | null = null): Promise<any> {
return new Promise((resolve, reject) => {
if (this.oss_type === 'ali') {
this.getFormData(this.fileData, this.filePath, this.fileName)
this.upload(progressCallback, this.formData)
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
} else {
this.getPutSignUrl(this.bucket, this.fileName, this.filePath, (error, presignedUrl) => {
if (error) reject(error)
this.hostUrl = presignedUrl
this.upload(progressCallback, this.fileData)
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
})
}
//--------------------------------------------------------------------------公网阿里云oss
/*******
* @description: 整理formData
* @param {*} fileData
* @param {*} filePath
* @param {*} fileName
* @return {*}
*/
getFormData(fileData: File, filePath: string, fileName: string): FormData {
const formData = new FormData()
formData.append('key', `${filePath}${fileName}`) // 存储在oss的文件路径
formData.append('OSSAccessKeyId', this.access_key) // accessKeyId
formData.append('policy', this.policy) // policy
formData.append('Signature', this.signature) // 签名
// 如果是base64文件,那么直接把base64字符串转成blob对象进行上传就可以了
formData.append('file', fileData)
formData.append('success_action_status', '200') // 成功后返回的操作码
this.formData = formData
return formData
}
//-------------------------------------------------------------------------------------------------局域网minIO存储
/*******
* @description: 创建minio客户端
* @param {*} config {endPoint:存储服务ip地址(xxx.xxx.xxx),port:端口,useSSL:是否使用ssl,accessKey:账号,secretKey:密码}
* @return {*}
*/
createMinio(config: {
endPoint: string
accessKey: string
secretKey: string
port: string
useSSL: boolean
sessionToken: string
}) {
if (!config) throw new Error('minio配置信息错误')
const minioClient = new Minio.Minio.Client(config)
this.minioClient = minioClient
}
/*******
* @description: 获取文件二进制流
* @param {*} fileData 文件数据
* @param {*} callBack 转换完成回调
* @return {*}
*/
getFileBuffer(fileData: File, callBack: (buffer: Buffer) => void) {
const reader = new FileReader()
reader.readAsArrayBuffer(fileData)
reader.onload = (e) => {
const res = e.target?.result as ArrayBuffer
const buffer = Buffer.from(res)
this.fileBuffer = buffer
callBack(buffer)
}
}
/*******
* @description: 获取签名后得上传地址
* @param {*} bucket String 私有化存储桶名称
* @param {*} fileName String 文件名称
* @param {*} filePath String 文件存储路径
* @param {*} validityTime number 上传链接有效期(秒,默认设置1小时)
* @return {*}
*/
getPutSignUrl(
bucket: string,
fileName: string,
filePath: string,
callBack: (error: any, presignedUrl: string) => void,
validityTime: number = 60 * 60 * 24
) {
this.minioClient?.bucketExists(bucket, (err) => {
if (err) throw new Error('minIO存储桶不存在')
this.minioClient?.presignedPutObject(
bucket,
`${filePath}${fileName}`,
validityTime,
(err, presignedUrl) => {
this.hostUrl = presignedUrl
callBack(err, presignedUrl)
}
)
})
return this.hostUrl
}
// --------------------------------------------------------上传
/*******
* @description: 上传
* @param {*} progressCallback 上传进度callback
* @return {*}
*/
upload(
progressCallback: ((progressEvent: ProgressEvent) => void) | null = null,
data: FormData | Buffer | null = this.formData || this.fileBuffer
): Promise<any> | undefined {
if (!data) return
const config: AxiosRequestConfig = {
url: this.hostUrl,
method: this.axiosMethod,
data,
withCredentials: false,
headers: {
'Content-Type': this.oss_type === 'ali' ? 'multipart/form-data' : this.fileType
},
// 监听上传进度
onUploadProgress: progressCallback,
// 取消上传方法
cancelToken: this.cancelToken?.token
}
return axios(config)
}
cancelUpload() {
this.cancelToken?.cancel()
this.cancelToken = null
}
setCancelToken() {
if (this.cancelToken) {
return this.cancelToken
}
}
}
具体使用还带看个人研究结合个人需求实际