El uso de progreso controlador cuando la carga de archivos a AWS S3 con Reaccionar

0

Pregunta

Yo soy sólo recientemente el trato con el SDK de AWS y por lo tanto por favor, disculpe si mi enfoque es una completa tontería.

Quiero subir un simple archivo de medios a mi S3. Yo estaba siguiendo este tutorial y por ahora no soy capaz de subir archivos sin problema. Para userbility una barra de progreso sería un buen extra y por lo tanto yo estaba investigando cómo lograr esto. Rápidamente me di cuenta de que el actual AWS SDK v3 no apoyo httpUploadProgress ya , pero debemos utilizar @aws-sdk/lib-storage en su lugar. El uso de esta biblioteca, aún soy capaz de subir archivos para el S3 pero no puedo conseguir el progreso tracker a la obra! Supongo que esto tiene algo que ver con que no me la plena comprensión de cómo lidiar con async dentro de un Reaccionan componente.

Así que aquí está mi record de componente ejemplo (estoy usando el Chakra de la interfaz de usuario de aquí)

const TestAWS: React.FC = () => {
  const inputRef = useRef<HTMLInputElement | null>(null);
  const [progr, setProgr] = useState<number>();

  const region = "eu-west-1";
  const bucketname = "upload-test";

  const handleClick = async () => {
    inputRef.current?.click();
  };

  const handleChange = (e: any) => {

    console.log('Start file upload');

    const file = e.target.files[0];
    const target = {
      Bucket: bucketname,
      Key: `jobs/${file.name}`,
      Body: file,
    };

    const s3 = new S3Client({
      region: region,
      credentials: fromCognitoIdentityPool({
        client: new CognitoIdentityClient({ region: region }),
        identityPoolId: "---MY ID---",
      }),
    });

    const upload = new Upload({
      client: s3,
      params: target,
    });

    const t = upload.on("httpUploadProgress", progress => {
      console.log("Progress", progress);

      if (progress.loaded && progress.total) {
        console.log("loaded/total", progress.loaded, progress.total);
        setProgr(Math.round((progress.loaded / progress.total) * 100)); // I was expecting this line to be sufficient for updating my component
      }
    });
    await upload.done().then(r => console.log(r));
  };

console.log('Progress', progr);

return (
    <InputGroup onClick={handleClick}>
      <input ref={inputRef} type={"file"} multiple={false} hidden accept='video/*' onChange={e => handleChange(e)} />
      <Flex layerStyle='uploadField'>
        <Center w='100%'>
          <VStack>
            <PlusIcon />
            <Text>Choose Video File</Text>
          </VStack>
        </Center>
      </Flex>
      {progr && <Progress value={progr} />}
    </InputGroup>
  );
};

export default TestAWS;

Así que, básicamente, veo el caso de ser despedido (inicio de carga de archivos). A continuación, toma un tiempo y veo que la Promesa de resultados y la Progress, 100 en mi consola. Esto para mí significa que la variable de estado se actualiza (al menos una vez), pero el componente no vuelva a representar?

¿Qué es lo que estoy haciendo mal aquí? Cualquier ayuda apreciada!

amazon-s3 aws-sdk reactjs
2021-11-22 15:34:31
2

Mejor respuesta

1

Bien, he encontrado la solución. La devolución de llamada en la variable de estado funciona bien y hace lo que debe. Pero la configuración de la Upload objeto estaba apagado. Después de cavar en la fuente me enteré de que el detector de eventos sólo se activa si el uploader ha subido más datos. Porque Uploader trozos de la carga que tiene dos separar los parámetros de configuración que le permiten dividir la carga en dos trozos. Así

const upload = new Upload({
  client: s3,
  params: target,
  queueSize: 4,          // 4 is minimum
  partSize: 5*1024*1024  // 5MB is minimum
});

básicamente hace el trabajo cuando el archivo se carga es mayor de 5MB! Sólo entonces el evento se activa de nuevo y actualiza la variable de estado.

Desde este cargador está hecho para el manejo de grandes cargas de archivos, esta totalmente de sentido y simplemente se podría ajustar queueSize y partSize según el archivo que queremos subir. Algo como

let queueSize = 10;
const file = event.target.files[0];

let partSize = file.size / (10 * 1024 * 1024);    // 1/10th of the file size in MB

const upload = new Upload({
  client: s3,
  params: target,
  queueSize: partSize > 5 queueSize : undefined,
  partSize: partSize > 5 ? partsize : undefined
});

Obviamente, esto se puede hacer mucho más sofisticado, pero no me quiero gastar demasiado tiempo en esto ya que no es parte de la pregunta original.

Conclusión

Si su archivo es lo suficientemente grande (>5 MB), podrás ver el progreso de la actualización, dependiendo del número de fragmentos (de 5 MB o más) que usted ha elegido para dividir el archivo.

Ya que esto sólo afecta a la handleChange método del ejemplo original, he puesto esto para la integridad

const handleChange = async ( event ) => {
  const file = event.target.files[0]

  const target = {
    Bucket: 'some-S3-bucket',
    Key: `jobs/${file.name}`,
    Body: file,
  };

  const s3 = new S3Client({
    region: 'your-region',
    credentials: fromCognitoIdentityPool({
      client: new CognitoIdentityClient({ region: 'your-region' }),
      identityPoolId: "your-id",
    }),
  });

  // this will default to queueSize=4 and partSize=5MB
  const upload = new Upload({
    client: s3,
    params: target
  });

  upload.on("httpUploadProgress", progress => {
    console.log('Current Progress', progress);
    setProgr(progress);
  });

  await upload.done().then(r => console.log(r));
} 

Tal vez esto ayude a alguien que tiene el mismo problema.

2021-11-22 18:06:15
1

Me encontré con tu respuesta después de tener exactamente el mismo problema (con Vue) de hoy!

De hecho, usted tiene razón: el SDK de AWS JS v3 evento sólo se desencadena por la parte que no es del todo claro y he perdido el tiempo de depuración que demasiado. Como para un archivo de 4 mb, lo único que haría sería jamás el fuego al 100%.

Como usted dice, usted puede experimentar con el tamaño de la parte , pero el mínimo es de 5MB y así en una conexión lenta me pareció puede parecer que una carga es atrapado como usted tiene que esperar para 5MB para obtener cualquier datos. Hmm. Así que lo que hice fue mirar el tamaño del archivo que está siendo cargado. Y si es menor que un umbral (decir 25MB, o lo que sea aplicable), así que es probablemente seguro para cargar todo en una sola vez, usted realmente no necesita de varias partes de subir. Y así yo también hizo un presigned URL (https://aws.amazon.com/blogs/developer/generate-presigned-url-modular-aws-sdk-javascript/) que puede ser utilizado para PONER el uso de axios (desde fetch no apoyar el progreso de los eventos aún).

De manera de que usted puede utilizar upload para archivos grandes (donde realmente se necesitan de varias partes de la carga y donde 5MB como un porcentaje del tamaño del archivo es pequeño), y el uso de un presigned URL para archivos pequeños y así obtener mucho más frecuentes actualizaciones.

El mismo progreso de controlador de eventos pueden ser utilizados por ambos.

this.$axios
  .request({
     method: "PUT",
     url: SIGNED-URL-HERE,
     data: file,
     timeout: 3600 * 1000,
     onUploadProgress: this.uploadProgress,
  })
  .then((data) => {
     console.log("Success", data);
  })
  .catch((error) => {
     console.log("Error", error.code, error.message);
  });

No es ideal, pero es una ayuda.

2021-11-24 00:54:55

Yo tenía la misma idea, pero para ser justos, supongo lib-storage nunca fue destinado a ser utilizado para los pequeños de la carga de archivos. Por desgracia, parece que actualmente no hay una solución satisfactoria cuando se utiliza v3 (ya que es mediante la recuperación de la api de bajo el capó) y la carga de archivos pequeños. Por lo que su enfoque es sin duda una buena solución, pero esperemos que implementar algo en el SDK muy pronto.
Flo Ragossnig

Estoy de acuerdo. Es muy molesto tener que usar una firma de URL como una solución, pero a menos que/hasta el SDK de cambios (tal vez cuando la recuperación de la API añade el progreso de subida) por ahora parece que usted tiene que escoger dependiendo de si multiparte o regular las actualizaciones de progreso es el más importante para su uso
coder_uk

En otros idiomas

Esta página está en otros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Slovenský
..................................................................................................................