React ile AWS S3'e dosya yüklerken ilerleme işleyicisini kullanma

0

Soru

Son zamanlarda AWS SDK ile uğraşıyorum ve bu nedenle yaklaşımım tamamen saçma ise lütfen özür dilerim.

S3'üme basit bir medya dosyası yüklemek istiyorum. Bu öğreticiyi takip ediyordum ve şimdiye kadar sorunsuz dosya yükleyebiliyorum. Kullanışlılık için bir ilerleme çubuğu güzel bir ekstra olurdu ve bu nedenle bunu nasıl başaracağımı araştırıyordum. Mevcut AWS SDK v3'ün desteklemediğini çabucak buldum httpUploadProgress artık ama kullanmalıyız@aws-sdk/lib-storage yerine. Bu kütüphaneyi kullanarak, hala S3'e dosya yükleyebiliyorum ancak ilerleme izleyicisinin çalışmasını sağlayamıyorum! Bunun nasıl başa çıkacağımı tam olarak anlamamamla bir ilgisi olduğunu varsayıyorum async bir React bileşeni içinde.

İşte benim minified bileşen örneğim (burada Çakra UI kullanıyorum)

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;

Yani temelde olayın kovulduğunu görüyorum (dosya yüklemeyi başlat). O zaman biraz zaman alır ve Söz sonucunu ve Progress, 100 konsolumda. Bu benim için durum değişkeninin güncellendiği (en az bir kez) ancak bileşenin yeniden oluşturulmadığı anlamına mı geliyor?

Burada neyi yanlış yapıyorum? Herhangi bir yardım takdir!

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

En iyi cevabı

1

Pekala, çözümü buldum. Durum değişkenindeki geri arama iyi çalışır ve yapması gerekeni yapar. Ama yapılandırma Upload nesne kapalıydı. Kaynağa girdikten sonra, olay dinleyicisinin yalnızca yükleyici daha fazla veri yüklediyse tetiklendiğini öğrendim. Yükleyici yüklemeleri parçaladığından, yüklemenizi ayrı parçalara ayırmanıza izin veren iki ayrı yapılandırma parametreniz vardır. Böyle

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

temel olarak, yüklediğimiz dosya 5mb'den büyük olduğunda işi yapar! Ancak o zaman olay tekrar tetiklenir ve durum değişkenini günceller.

Bu yükleyici büyük dosya yüklemelerini işlemek için yapıldığından, bu tamamen mantıklıdır ve basitçe ayarlayabiliriz queueSize ve partSize yüklemek istediğimiz dosyaya göre. Aşağı yukarı

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

Açıkçası, bu çok daha karmaşık yapılabilir, ancak orijinal sorunun bir parçası olmadığı için bu konuda çok fazla zaman harcamak istemedim.

Sonuç

Eğer dosya yeterince büyük (>5 MB), göreceksiniz ilerleme güncellemesi, ona göre sayıda parçalar (en 5 MB ya da daha fazla) seni seçtiği için split dosyası.

Bu sadece aşağıdakileri etkilediğinden handleChange orijinal örnekten yöntem, bunu tamlık için gönderiyorum

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

Belki bu aynı sorunu yaşayan birine yardım eder.

2021-11-22 18:06:15
1

Bugün tam olarak aynı sorunu yaşadıktan sonra (Vue ile) cevabınıza rastladım!

Gerçekten de haklısınız: AWS SDK JS v3 olayı yalnızca parça başına tetiklenir, bu da hiç net değildir ve bunu da hata ayıklamak için zaman harcadım. 4MB'LIK bir dosya için olduğu gibi, yalnızca %100'de ateşlenir.

Olarak söyle, sen deney parçası boyutu ama en azından 5 MB ve çok yavaş bir bağlantı buldum bunu görünen bir upload kalmış gibi seni beklemek için 5 MB için elde herhangi bir veri. Hmm. Yaptığım şey yüklenen dosyanın boyutuna bakmaktı. Ve eğer bir eşiğin altındaysa (25MB veya uygulanabilir olan her neyse), çok parçalı yüklemeye gerçekten ihtiyaç duymadığınız için hepsini tek seferde yüklemek muhtemelen güvenlidir. Ve böylece önceden imzalanmış bir URL de yaptım (https://aws.amazon.com/blogs/developer/generate-presigned-url-modular-aws-sdk-javascript/) axios kullanarak koymak için kullanılabilir (çünkü fetch ilerleme olaylarını henüz desteklemiyor).

Böylece bu şekilde kullanabilirsiniz upload büyük dosyalar için (aslında çok parçalı yüklemeye ihtiyaç duyduğunuz ve dosya boyutunun yüzdesi olarak 5mb'nin küçük olduğu yerlerde) ve küçük dosyalar için önceden imzalanmış bir URL kullanın ve böylece çok daha sık güncellemeler alın.

Aynı ilerleme olay işleyicisi her ikisi tarafından da kullanılabilir.

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

İdeal değil ama yardımcı oluyor.

2021-11-24 00:54:55

Ben de aynı fikirdeydim ama adil olmak gerekirse, sanırım lib-storage hiçbir zaman küçük dosya yüklemeleri için kullanılmak üzere tasarlanmamıştı. Ne yazık ki, v3'ü kullanırken (kaputun altındaki getirme apı'sini kullandığı için) ve küçük dosyaları yüklerken şu anda tatmin edici bir çözüm yok gibi görünüyor. Bu yüzden yaklaşımınız kesinlikle iyi bir geçici çözümdür, ancak umarım çok yakında sdk'da bir şeyler uygulayacaklardır.
Flo Ragossnig

Katılıyorum. İmzalı bir URL'yi geçici bir çözüm olarak kullanmak can sıkıcıdır, ancak SDK değişene kadar (belki de getirme API'sı yükleme ilerlemesini eklediğinde) şimdilik çok parçalı veya düzenli ilerleme güncellemelerinin kullanımınız için en önemli olup olmadığına bağlı olarak seçmeniz gerekir
coder_uk

Diğer dillerde

Bu sayfa diğer dillerde

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