eos分片上传

239 阅读2分钟

大文件分片上传: 1、确认分块的维度,创建分块上传,获取到uploadId作为分块上传标识 2、传入uploadId进行分块上传,获取到每个分块独有的Etag 3、成功上传所有相关部分后,将分块整合成一个完整的文件。对象存储服务将按部件编号升序连接所有部件以创建新文件

import {
  ossInfo,
  reviewUrl,
  eosInfo,
  getEosSign,
  uploadEosCallback,
} from "@/api/publicFile";
import { message } from "ant-design-vue";
export const uploadFile = async (params) => {
    if(!params.file) {
      message.error("文件上传失败!")
      return
    }
    return uploadByEos(params)
};

/** eos 上传 */
const uploadByEos = async params => {
  console.log(params.file.size)
  return params.file.size > 1024 * 1024 * 50
    ? uploadByEosMultipart(params)
    : uploadByEosDirect(params)
}

/** eos 直传 */
const uploadByEosDirect = async params => {
  const res = await getEosSign()
  let s3 = new AWS.S3({
    accessKeyId: res.data?.accessKeyId,
    secretAccessKey: res.data?.secretAccessKey,
    endpoint: res.data?.endpoint,
    region: res.data?.region,
    sessionToken: res.data?.sessionToken
  })
  const fileInfo = {
    Key: `${res.data?.key}${params.file.name}`,
    Bucket: res.data?.bucket,
    ContentType: params.file.type, 
    Body: params.file,
  }
  return new Promise((resolve,reject) => {
    return s3.putObject(fileInfo, async function(err, data){
      if(err) {
        reject(err)
        return message.error(err)
      }
      const fileData = {
        etag: JSON.parse(data.ETag),
        key: `${res.data?.key}${params.file.name}`,
        filename: params.file.name,
        size: params.file.size
      }
      const value = await uploadEosCallback(fileData)
      resolve(value)
    })
  })
}

/** eos 分片 */
const uploadByEosMultipart = async params => {
  const res = await getEosSign()
  const s3 = new AWS.S3({
    accessKeyId: res.data?.accessKeyId,
    secretAccessKey: res.data?.secretAccessKey,
    endpoint: res.data?.endpoint,
    region: res.data?.region,
    sessionToken: res.data?.sessionToken
  })

  const key = `${res.data?.key}${params.file.name}`
  const bucket = res.data?.bucket

  const { UploadId: uploadId } = await createMultipartUpload({
    key,
    file: params.file,
    bucket,
    s3
  })

  const parts = await uploadEosPart({ key, file: params.file, bucket, uploadId, s3 })
  const { ETag } = await completeUploadEosPart({ key, bucket, uploadId, parts, s3 })

  const fileData = {
    etag: ETag,
    key,
    filename: params.file.name,
    size: params.file.size
  }
  return await uploadEosCallback(fileData)
}

const createMultipartUpload = ({ key, file, bucket, s3 }) => {
  let fileInfo = {
    Key: key,
    Bucket: bucket,
    // ACL: "private"
  }
  return new Promise((resolve, reject) => {
    s3.createMultipartUpload(
      fileInfo,
      (err, data) => {
        if(err) {
          reject(err)
          return message.error(err)
        }
        resolve(data)
      }
    )
  })
}

const uploadEosPart = async ({ key, file, bucket, uploadId, s3 }) => {
  const chunkSize = 1024 * 1024 * 5 // 每个切片的大小
  const totalChunks = Math.ceil(file.size / chunkSize)
  const parts = []
  for(let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize
    const end = start + chunkSize
    const value = {
      Body: file.slice(start, end),
      Bucket: bucket,
      Key: key,
      PartNumber: i + 1 ,
      UploadId: uploadId
    }
    const { ETag } = await uploadEosPartApi(value, { s3 })
    parts.push({ ETag, PartNumber: value.PartNumber })
  }
  return parts
}

// eos 分片上传 api promise
const uploadEosPartApi = (value, { s3 }) => {
  return new Promise((resolve, reject) => {
    s3.uploadPart(value, function(err, data) {
      if(err) {
        reject(err)
        return message.error(err)
      }
      resolve(data)
    })
  })
}

// eos 完成分片上传 api promise
const completeUploadEosPart= ({ key, bucket, uploadId, parts, s3 }) => {
  const fileData = {
    Bucket: bucket,
    Key: key,
    MultipartUpload: {
      Parts: parts
    },
    UploadId: uploadId
  }
  return new Promise((resolve, reject) => {
    s3.completeMultipartUpload(fileData, function(err, data) {
      if(err) {
        reject(err)
        return message.error(err)
      }
      resolve(data)
    })
  })
}