El cliente implementa la carga de archivos de Alibaba Cloud OSS (carga de fragmentos, reanudación de punto de interrupción)

prefacio

Alibaba Cloud OSS (Object Storage Service) es un servicio de almacenamiento en la nube estable, seguro y altamente escalable que le permite almacenar y acceder a cualquier tipo de datos de manera económica, altamente confiable y altamente disponible. En aplicaciones prácticas, la carga de archivos es un requisito funcional común. Para mejorar la eficiencia de la carga y la integridad de los archivos, podemos utilizar la tecnología de carga de varias partes y reanudar la carga.

Escenarios de uso de carga de segmentos y carga de puntos de interrupción:
por lo general, cuando el archivo tiene más de 100 MB, se recomienda adoptar el método de carga de segmentos y mejorar la tasa de éxito de la carga al reanudar la carga en los puntos de interrupción y volver a intentarlo. Si utiliza la carga de varias partes cuando el archivo tiene menos de 100 MB y la configuración de tamaño de parte no es razonable, es posible que el progreso de la carga no se muestre por completo. Para archivos de menos de 100 MB, se recomienda utilizar el método de carga simple.

Referencia de carga simple: https://help.aliyun.com/zh/oss/developer-reference/simple-upload-8?spm=a2c4g.11186623.0.0.3f742a44LqLGSc

A continuación, presentaremos cómo usar la carga de fragmentos y la carga reanudable en el proyecto vue.

Preparar

1. Instale el SDK de OSS de la nube de Alibaba

npm install ali-oss --save

2. Crear SFA

import OSS from "ali-oss";
const client = ref(
  new OSS({
    
    
    // yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。
        region: 'yourRegion',
        // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
        accessKeyId: 'yourAccessKeyId',
        accessKeySecret: 'yourAccessKeySecret',
        // 填写Bucket名称。
        bucket: 'examplebucket'
  })
);

Carga de varias partes

Pasos para la carga de varias partes:

  1. Inicializar la carga de varias partes: llame a la API de OSS para inicializar una sesión de carga de varias partes y obtener una ID de carga. El ID de carga se utiliza para identificar esta operación de carga de varias partes.
  2. Corte de fragmentos: corte el archivo grande que se cargará en fragmentos de tamaño fijo.
  3. Cargue fragmentos uno por uno: cargue cada fragmento en Alibaba Cloud OSS uno por uno en orden, y se devolverá una ETag después de que cada fragmento se cargue correctamente para identificar el fragmento.
  4. Carga completa de la parte: después de cargar todas las partes, llame a la API de OSS para completar la operación de carga de la parte. En este paso, la ETag y el número de fragmento de cada fragmento deben pasarse a OSS en orden, y OSS combinará los fragmentos de acuerdo con esta información para formar un archivo grande completo.

Código:

const uploadProgress = ref(0); //上传进度
const paused = ref(false); //是否暂停
const name = ref(""); //文件名
const uploadId = ref(); //上传id
const chunkArr: any = ref([]);//分片上传的结果数组
let chunks: any = [];//文件分片结果
const uploadFile1 = async (file: any) => {
    
    
  chunkArr.value = [];
  uploadProgress.value = 0;
  //获取文件分片的结果数组
  chunks =sliceFile(file);
  const {
    
     name: fileName, type: mimeType } = file;
  name.value = fileName;
  //初始化分片上传,获取Upload ID
  const result = await client.value.initMultipartUpload(fileName);
  uploadId.value = result.uploadId;
  //分片上传
  uploadChunk(chunks[0], 1);
};

// 分片
const chunkSize = ref(1 * 1024 * 1024); //分片大小
const size = ref(0);//文件大小
const sliceFile = (file: any) => {
    
    
  const fileSize = file.size;
  size.value = file.size;
  const chunks = Math.ceil(fileSize / chunkSize.value); // 计算分片总数
  const allChunks = [];
  for (let i = 0; i < chunks; i++) {
    
    
    const start = i * chunkSize.value;
    const end = Math.min(start + chunkSize.value, fileSize);
    const chunk = file.slice(start, end);
    allChunks.push(chunk);
  }
  return allChunks;
};

//上传
async function uploadChunk(chunk: any, partNumber: number) {
    
    
  //判断是否暂停上传
  if (paused.value) {
    
    
    paused.value = false;
    return;
  }
  //上传分片
  const part = await client.value.uploadPart(
    name.value,
    uploadId.value,
    partNumber,
    chunk,
    0,
    chunk.size
  );
  chunkArr.value.push({
    
     number: partNumber, etag: part.etag });
  // 获取进度
  uploadProgress.value = Number(
    ((partNumber / chunks.length) * 100).toFixed(2)
  );
  if (partNumber < chunks.length) {
    
    
    //分片上传成功
    partNumber++;
    uploadChunk(chunks[partNumber - 1], partNumber);
  } else {
    
    
    // 分片全部上传完毕
    await client.value.completeMultipartUpload(
      name.value,
      uploadId.value,
      chunkArr.value
    );
  }
}

Carga de documento oficial en piezas

http

//暂停上传
const stop = () => {
    
    
  paused.value = true;
};

//继续上传(断点续传)
const continued = () => {
    
    
  client.value.listParts(name.value, uploadId.value).then((result: any) => {
    
    
    //获取已经上传分片的信息
    var parts = result.parts || [];
    var nextPartNumber = parts.length + 1;
    //继续上传未上传的分片
    uploadChunk(chunks[nextPartNumber - 1], nextPartNumber);
  });
};

caso completo

<template>
  <el-upload
    v-model:file-list="fileList"
    class="upload-demo"
    :before-upload="beforeUpload"
  >
    <div class="upload">
      <el-button type="primary">Click to upload</el-button>
      <el-progress
        :percentage="uploadProgress"
        type="line"
        style="margin-left: 10px; width: 350px"
      >
      </el-progress>
    </div>
  </el-upload>
  <el-button type="primary" size="small" @click="stop">暂停</el-button>
  <el-button type="primary" size="small" @click="continued">继续</el-button>
</template>
<script setup lang="ts">
import {
    
     ref } from "vue";
import {
    
     ElMessage, ElMessageBox, progressProps } from "element-plus";
import OSS from "ali-oss";
import type {
    
     UploadProps, UploadUserFile } from "element-plus";
const client = ref(
  new OSS({
    
    
    // yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。
        region: 'yourRegion',
        // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
        accessKeyId: 'yourAccessKeyId',
        accessKeySecret: 'yourAccessKeySecret',
        // 填写Bucket名称。
        bucket: 'examplebucket'
  })
);
const beforeUpload = async (file: File) => {
    
    
  try {
    
    
    await uploadFile(file);
  } catch (error) {
    
    
    console.error("Error uploading file:", error);
  }
  return false;
};
//分片上传
const fileList = ref<UploadUserFile[]>([]);
const uploadProgress = ref(0); //上传进度
const paused = ref(false); //是否暂停
const name = ref(""); //文件名
const uploadId = ref(); //上传id
const chunkArr: any = ref([]);//分片上传的结果数组
let chunks: any = [];//文件分片结果
const uploadFile = async (file: any) => {
    
    
  chunkArr.value = [];
  uploadProgress.value = 0;
  //获取文件分片的结果数组
  chunks =sliceFile(file);
  const {
    
     name: fileName, type: mimeType } = file;
  name.value = fileName;
  //初始化分片上传,获取Upload ID
  const result = await client.value.initMultipartUpload(fileName);
  uploadId.value = result.uploadId;
  //分片上传
  uploadChunk(chunks[0], 1);
};

// 分片
const chunkSize = ref(5 * 1024 * 1024); //分片大小
const size = ref(0);//文件大小
const sliceFile = (file: any) => {
    
    
  const fileSize = file.size;
  size.value = file.size;
  const chunks = Math.ceil(fileSize / chunkSize.value); // 计算分片总数
  const allChunks = [];
  for (let i = 0; i < chunks; i++) {
    
    
    const start = i * chunkSize.value;
    const end = Math.min(start + chunkSize.value, fileSize);
    const chunk = file.slice(start, end);
    allChunks.push(chunk);
  }
  return allChunks;
};

//上传
async function uploadChunk(chunk: any, partNumber: number) {
    
    
  //判断是否暂停上传
  if (paused.value) {
    
    
    paused.value = false;
    return;
  }
  //上传分片
  const part = await client.value.uploadPart(
    name.value,
    uploadId.value,
    partNumber,
    chunk,
    0,
    chunk.size
  );
  chunkArr.value.push({
    
     number: partNumber, etag: part.etag });
  // 获取进度
  uploadProgress.value = Number(
    ((partNumber / chunks.length) * 100).toFixed(2)
  );
  if (partNumber < chunks.length) {
    
    
    //分片上传成功
    partNumber++;
    uploadChunk(chunks[partNumber - 1], partNumber);
  } else {
    
    
    // 分片全部上传完毕
    await client.value.completeMultipartUpload(
      name.value,
      uploadId.value,
      chunkArr.value
    );
  }
}
//暂停上传
const stop = () => {
    
    
  paused.value = true;
};

//继续上传(断点续传)
const continued = () => {
    
    
  client.value.listParts(name.value, uploadId.value).then((result: any) => {
    
    
    //获取已经上传分片的信息
    var parts = result.parts || [];
    var nextPartNumber = parts.length + 1;
    //继续上传未上传的分片
    uploadChunk(chunks[nextPartNumber - 1], nextPartNumber);
  });
};

</script>

<style lang="scss" scoped>
.upload {
    
    
  display: flex;
}
</style>

inserte la descripción de la imagen aquí

Problemas encontrados y soluciones:

Pregunta 1: Problema entre dominios
https://blog.csdn.net/StruggleRookie/article/details/119417281

Pregunta 2: se produce el error "Por favor, configure el etag de los encabezados expuestos en OSS" al cargar un archivo usando la función de carga multiparte OSS
https://help.aliyun.com/zh/oss/the-please-set-the-etag -of-expose-headers-in-oss-error-message-es-devuelto-cuando-usa-multipart-upload-to-upload-files

Supongo que te gusta

Origin blog.csdn.net/CYL_2021/article/details/132003653
Recomendado
Clasificación