Node.js (AWS SDK v3) i HostArena S3: primeri koda

Node.js (AWS SDK v3) i HostArena S3: primeri koda

AWS SDK za JavaScript (verzija 3) je zvanična biblioteka za rad sa S3 skladištem iz Node.js aplikacija. Sa HostArena S3 storage je koristite isto kao sa Amazon S3, uz tri razlike u podešavanju: adresa servera, region garage i uključen forcePathStyle.

Šta vam je potrebno

PodatakVrednostGde ga nalazite
Endpointhttps://s3.hostarena.rsIsti za sve korisnike
RegiongarageObavezno tačno ovako
Bucketvas-bucketHostArena korisnički panel, kod S3 usluge
Access KeyVAS_ACCESS_KEYHostArena korisnički panel, kod S3 usluge
Secret KeyVAS_SECRET_KEYHostArena korisnički panel, kod S3 usluge

Potreban vam je Node.js, aktuelna LTS verzija.

Koraci

  1. Napravite projekat i instalirajte S3 modul:

    mkdir s3-primer
    cd s3-primer
    npm init -y
    npm install @aws-sdk/client-s3
  2. Ključeve ne upisujte direktno u kod. Postavite ih kao promenljive okruženja. Na Linux-u i macOS-u:

    export AWS_ACCESS_KEY_ID="VAS_ACCESS_KEY"
    export AWS_SECRET_ACCESS_KEY="VAS_SECRET_KEY"

    U Windows PowerShell-u:

    $env:AWS_ACCESS_KEY_ID="VAS_ACCESS_KEY"
    $env:AWS_SECRET_ACCESS_KEY="VAS_SECRET_KEY"

    Ove komande važe za otvoreni terminal. Na serveru ih obično upisujete u podešavanja servisa, u .env fajl koji se ne objavljuje ili u alat za tajne podatke.

  3. Napravite fajl primer.js. Sav kod je u async funkcijama, jer SDK radi asinhrono, a await van funkcije ne radi u CommonJS fajlu. Primer otprema fajl, ispisuje spisak i preuzima fajl tako da ga stvarno snimi na disk:

    const fs = require("node:fs");
    const { pipeline } = require("node:stream/promises");
    const {
      S3Client,
      ListObjectsV2Command,
      PutObjectCommand,
      GetObjectCommand,
      DeleteObjectCommand,
    } = require("@aws-sdk/client-s3");
    
    // Ključevi se čitaju iz promenljivih okruženja
    // AWS_ACCESS_KEY_ID i AWS_SECRET_ACCESS_KEY.
    const s3 = new S3Client({
      endpoint: "https://s3.hostarena.rs",
      region: "garage",
      forcePathStyle: true,
    });
    
    const BUCKET = "vas-bucket";
    
    // Otpremanje lokalnog fajla u bucket.
    async function uploadFile(localPath, key) {
      await s3.send(
        new PutObjectCommand({
          Bucket: BUCKET,
          Key: key,
          Body: fs.createReadStream(localPath),
          ContentLength: fs.statSync(localPath).size,
        })
      );
      console.log("Otpremljeno:", key);
    }
    
    // Spisak fajlova u bucketu (prvih do 1000).
    async function listFiles() {
      const result = await s3.send(new ListObjectsV2Command({ Bucket: BUCKET }));
      for (const obj of result.Contents ?? []) {
        console.log(obj.Key, obj.Size, "bajtova");
      }
    }
    
    // Preuzimanje fajla iz bucketa i snimanje na disk.
    async function downloadFile(key, localPath) {
      const result = await s3.send(new GetObjectCommand({ Bucket: BUCKET, Key: key }));
      await pipeline(result.Body, fs.createWriteStream(localPath));
      console.log("Snimljeno:", localPath);
    }
    
    // Brisanje fajla iz bucketa.
    async function deleteFile(key) {
      await s3.send(new DeleteObjectCommand({ Bucket: BUCKET, Key: key }));
      console.log("Obrisano:", key);
    }
    
    async function main() {
      await uploadFile("bekap.zip", "bekapi/bekap.zip");
      await listFiles();
      await downloadFile("bekapi/bekap.zip", "vraceno.zip");
    }
    
    main().catch((err) => {
      // err.name sadrži S3 kod greške, npr. NoSuchKey ili AccessDenied
      console.error("Greška:", err.name, "-", err.message);
      process.exitCode = 1;
    });

    Kod preuzimanja, result.Body je tok podataka (stream). Funkcija pipeline ga upisuje u fajl i čeka da upis bude završen. Bez toga biste dobili samo odgovor servera, a fajl ne bi bio snimljen.

  4. Pokrenite primer (u istom terminalu u kom ste postavili ključeve):

    node primer.js

Korisno je znati

  • ListObjectsV2Command vraća najviše 1000 fajlova odjednom. Za veće buckete koristite paginateListObjectsV2 iz istog modula.
  • Za velike fajlove postoji modul @aws-sdk/lib-storage (klasa Upload), koji fajl deli na delove.
  • Funkcija deleteFile je u primeru definisana, ali se ne poziva. Pozovite je samo kada zaista želite da obrišete fajl.

Pažnja: DeleteObjectCommand trajno briše fajl i ne pita za potvrdu. Obrisani fajl se ne može vratiti.

Provera da radi

Stavite mali fajl bekap.zip u folder projekta i pokrenite node primer.js. Ispravan ispis je „Otpremljeno”, spisak fajlova i „Snimljeno: vraceno.zip”, a fajl vraceno.zip se pojavljuje u folderu. Ako vidite „Greška:”, iza nje stoji S3 kod greške.

Najčešći problemi

AuthorizationHeaderMalformed

Region nije dobar. Mora biti tačno garage. Sa us-east-1 ili bilo kojim drugim AWS regionom server odbija zahtev.

InvalidAccessKeyId, AccessDenied ili SignatureDoesNotMatch

Proverite da li su promenljive okruženja postavljene u istom terminalu ili servisu u kom pokrećete program i da ključevi nemaju razmak na početku ili kraju. Ključeve proverite u HostArena korisničkom panelu, kod S3 usluge.

NoSuchBucket

Naziv bucketa nije tačan. Prepišite ga iz HostArena korisničkog panela. Endpoint ostaje https://s3.hostarena.rs, bez naziva bucketa u adresi.

Greška vezana za checksum pri otpremanju

Novije verzije AWS SDK-a same dodaju kontrolni zbir (checksum) svakom otpremanju. Ako dobijete grešku koja pominje checksum, dodajte u podešavanja klijenta sledeće dve opcije:

const s3 = new S3Client({
  endpoint: "https://s3.hostarena.rs",
  region: "garage",
  forcePathStyle: true,
  requestChecksumCalculation: "WHEN_REQUIRED",
  responseChecksumValidation: "WHEN_REQUIRED",
});

Zaključak

Isti princip važi i za druge jezike: PHP, Python (boto3) i Go. Tehnički detalji o adresama i potpisivanju zahteva nalaze se u uputstvu HostArena S3 API: adrese, potpisivanje i kompatibilnost. Nemate S3 uslugu? Pogledajte pakete na stranici HostArena S3 storage. Ako zapne, otvorite tiket u korisničkom panelu.

Tags: , , ,