Pomocí pokrok psovoda při nahrávání souborů do AWS S3 s Reagovat

0

Otázka

Já jsem jen v poslední době jednání s AWS SDK a tak prosím omluvte, jestli můj přístup je úplný nesmysl.

Chci nahrát jednoduchý mediální soubor na můj S3. Byl jsem po tomto kurzu , a tak daleko jsem schopen nahrát soubory bez problému. Pro userbility progress bar by to být pěkný extra, a proto jsem hledal, jak toho dosáhnout. Rychle jsem zjistil, že aktuální AWS SDK v3 nepodporuje httpUploadProgress jsme ale měli použít @aws-sdk/lib-storage místo. Pomocí této knihovny jsem stále schopen nahrát soubory na S3, ale nemůžu se dostat pokroku tracker do práce! Předpokládám, že to má něco společného se mnou ne zcela pochopit, jak se vypořádat s async v rámci Reagovat komponenty.

Takže tady je můj minified složka příklad (já používám Čakra UI zde)

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;

Takže v podstatě vidím případě vyhazov (start upload souboru). Pak to chvíli trvá, a vidím, Slib výsledek a Progress, 100 v mé konzole. To pro mě znamená, že stát proměnná dostane aktualizovány (alespoň jednou), ale komponenta není re-render?

Co je to, co dělám špatně? Ocenil jakoukoliv pomoc!

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

Nejlepší odpověď

1

V pořádku, našel jsem řešení. Zpětné volání na stavu proměnné funguje a dělá to, co je třeba. Ale konfigurace Upload objekt byl pryč. Po kopání do zdroje jsem zjistil, že posluchače událostí, pouze se spustí, pokud uploader nahrál více údajů. Protože Umístil kousky, obrázky máte dva samostatné konfigurační parametry, které vám umožní rozdělit váš nahrát do samostatné kusy. Tak

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

v podstatě dělá práci, když soubor jsme nahrát je větší než 5MB! Teprve pak událost se spustí znovu a aktualizace stavu proměnné.

Protože tento uploader je určen pro zpracování velkých souborů na server, to úplně dává smysl, a můžeme jednoduše upravit queueSize a partSize podle k souboru, který chceme nahrát. Něco jako

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

Samozřejmě, to může být provedeno mnohem více sofistikované, ale nechtěl jsem trávit příliš mnoho času na to, protože to není součástí původní otázku.

Závěr

Pokud váš soubor je dostatečně velký (>5 MB), budete vidět pokrok aktualizovat, v závislosti na počtu bloků (5 MB nebo více) jste se rozhodli rozdělit váš soubor.

Protože to má vliv pouze na handleChange metoda z původního příkladu, jsem tento post pro úplnost

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

Možná to někomu pomůže, kdo má stejný problém.

2021-11-22 18:06:15
1

Narazil jsem na vaši odpověď, poté, co přesně stejný problém (s Vue) dnes!

Skutečně máte pravdu: AWS SDK JS v3 případě pouze požáry za část , která není vůbec jasné, a jsem ztracený čas ladění, že příliš. Pro 4MB souboru, bylo by to jen někdy střílet na 100%.

Jak říkáte, můžete experimentovat s velikost dílu , ale minimum je 5 MB a tak na pomalé připojení jsem zjistil, to se může zdát, že upload je přilepená, jak budete muset čekat na 5MB získat žádné údaje. Hmm. Takže to, co jsem udělal, bylo se podívat na velikost souboru, který je nahrán. A pokud je pod prahovou hodnotou (řekněme 25MB, nebo cokoliv, co je relevantní), tak je to pravděpodobně bezpečné nahrát to vše v jednom jít, protože nemáte opravdu potřebují multipart upload. A tak jsem také udělal presigned URL (https://aws.amazon.com/blogs/developer/generate-presigned-url-modular-aws-sdk-javascript/), které mohou být použity k DÁT pomocí axios (od fetch nepodporuje průběh události zatím).

Tak, že způsob, jak můžete použít upload pro velké soubory (kde skutečně potřebujete multipart upload a kde 5MB jako procento z velikosti souboru je malý), a použít presigned URL pro malé soubory, a tak získat mnohem více časté aktualizace.

Stejný pokrok obslužné rutiny události mohou být použity jak.

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

Není ideální, ale pomáhá.

2021-11-24 00:54:55

Měl jsem stejný nápad, ale aby to bylo fér, hádám, že lib-storage nikdy neměl být použit pro malé nahrání souboru. Bohužel, zdá se, že v současné době neexistuje žádné uspokojující řešení při použití v3 (protože to je pomocí fetch api pod kapotou) a nahrávání malých souborů. Takže tvůj přístup je určitě dobré řešení, ale doufejme, že se bude realizovat něco, co v SDK velmi brzy.
Flo Ragossnig

Souhlasím. Je to nepříjemné, museli použít signed URL jako řešení, ale pokud/dokud SDK změny (možná, když je fetch API přidává upload progress) teď to vypadá, budete muset vybrat v závislosti na tom, zda multipart nebo pravidelné aktualizace pokroku je nejdůležitější, aby vaše použití
coder_uk

V jiných jazycích

Tato stránka je v jiných jazycích

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