Folosind progresul handler, atunci când încărcarea fișierelor la AWS S3 cu Reacționa

0

Problema

Eu sunt doar recent de-a face cu AWS SDK și, astfel, vă rugăm să scuză dacă abordarea mea este un nonsens complet.

Vreau să încărcați un simplu fișier media la S3-ul meu. Am urmat acest tutorial si pana acum sunt capabil de a încărca fișiere fără nici o problemă. Pentru userbility o bară de progres va fi un plus frumos și, prin urmare, am fost cercetat modul de a realiza acest lucru. Am aflat destul de repede că actuala AWS SDK v3 nu are suport httpUploadProgress mai dar ar trebui să utilizați @aws-sdk/lib-storage în schimb. Folosind această bibliotecă, sunt în continuare capabil de a încărca fișiere la S3 dar eu nu pot obține progres tracker de la locul de muncă! Presupun că asta are ceva de-a face cu mine nu înțelege pe deplin cum să se ocupe cu async într-un Reacționa componentă.

Deci, aici este meu minified componentă exemplu (eu sunt, folosind Chakra UI aici)

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;

Deci, practic eveniment concediat (start upload). Apoi este nevoie de un timp și văd Promisiunea rezultatul și Progress, 100 în consola mea. Acest lucru înseamnă că variabila de stare devine actualizate (cel puțin o dată), dar componenta nu se re-face?

Ce este ceea ce fac greșit aici? Orice ajutor apreciat!

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

Cel mai bun răspuns

1

Bine, am gasit solutia. Callback pe variabilă de stat funcționează bine și nu face ceea ce ar trebui. Dar configurația Upload obiectul a fost oprit. După săpat în sursă am aflat că ascultător eveniment doar se declanșat dacă încărcare a încărcat mai multe date. Pentru că Uploader bucăți de încărcări aveți două parametri de configurare care vă permite să împărți incarca separat în bucăți. Deci

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

practic are loc de muncă atunci când fișierul ne incarca este mai mare decât 5MB! Numai atunci evenimentul se declanșat din nou și actualizări de variabila de stare.

Deoarece această încărcare se face pentru manipularea mari încărcări de fișiere, în acest sens și am putea pur și simplu a regla queueSize și partSize potrivit fișier vrem să încărcați. Ceva de genul

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
});

Evident, acest lucru poate fi făcut mult mai sofisticate, dar nu vreau să-și petreacă prea mult timp pe acest lucru, deoarece nu este parte din întrebarea inițială.

Concluzie

Dacă fișierul este suficient de mare (>5MB), veți vedea progresul actualizare, în funcție de numărul de bucăți (de 5MB sau mai multe) trebuie alese pentru a împărți fișier.

Deoarece aceasta afectează numai handleChange metoda de original exemplu, am posta acest pentru complet

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));
} 

Poate că acest lucru îi ajută pe cineva care are aceeasi problema.

2021-11-22 18:06:15
1

Am dat peste raspunsul tau dupa ce au exact aceeasi problema (cu Vue) de azi!

Într-adevăr, aveți dreptate: AWS SDK JS v3 eveniment, trage doar pe partea care nu este deloc clară și mi-am irosit timpul de depanare asta. Ca pentru un 4MB fișier, acesta ar fi doar vreodată foc la 100%.

Cum ai spus, puteți experimenta cu dimensiunea parte dar minimul este de 5MB și deci pe o conexiune lentă-am găsit poate apărea ca o încărcare este blocat ca va trebui să așteptați pentru 5MB pentru a obține orice date. Hmm. Deci ce am făcut a fost să se uite la dimensiunea de fișier a fi încărcate. Și dacă acesta este sub un prag (spune 25MB, sau cum este aplicabil), bine este, probabil, sigur să încarce toate într-un du-te ca nu ai nevoie de mai multe încărcarea. Și așa că am , de asemenea, a făcut o presigned URL (https://aws.amazon.com/blogs/developer/generate-presigned-url-modular-aws-sdk-javascript/), care poate fi folosit pentru a PUNE folosind axios (din fetch nu are suport pentru progresul evenimente încă).

Deci, în acest fel puteți utiliza upload pentru fișiere mari (în cazul în care aveți de fapt nevoie de mai multe încărcarea și în cazul în care 5MB ca un procent din dimensiunea fișierului este de mici), și de a folosi un presigned URL-ul pentru fișiere mici și deci se obține mult mai multe actualizări frecvente.

Același progres event handler poate fi utilizat de către ambele.

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);
  });

Nu este ideal, dar ajută.

2021-11-24 00:54:55

Am avut aceeași idee, dar pentru a fi corect, cred lib-storage nu a fost niciodată menit să fie folosit pentru mici încărcări de fișiere. Din păcate, se pare că nu există în prezent nici o soluție satisfăcătoare atunci când se utilizează v3 (deoarece este folosind aduce api sub capota) și încărcarea de fișiere mici. Deci, abordarea ta este cu siguranta o soluție bună, dar sperăm că se va pune în aplicare ceva în SDK foarte curând.
Flo Ragossnig

Sunt de acord. E enervant de a avea de a utiliza semnat un URL ca o soluție, dar dacă/până la SDK modificări (poate că atunci când aduce API adaugă progresul upload) acum se pare că trebuie să alegi în funcție de mai multe sau regulat actualizări de progres este cel mai important pentru dvs. de utilizare
coder_uk

În alte limbi

Această pagină este în alte limbi

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