Hyrje:

Kur bëhet fjalë për t'u ofruar përdoruesve mundësinë për të shkarkuar skedarë të shumtë nga Amazon S3 në një paketë të vetme, zipja e këtyre skedarëve është një kërkesë e zakonshme. Sidoqoftë, në një mjedis pa server si AWS Lambda, ka kufizime të ruajtjes dhe kujtesës që duhet të merren parasysh. Në këtë artikull, ne do të shqyrtojmë se si të zipni në mënyrë efikase skedarët e ruajtur në Amazon S3 duke përdorur Node.js, duke kapërcyer këto kufizime. Ne do të shfrytëzojmë transmetime të lexueshme dhe të shkruhet, së bashku me bibliotekën e arkivuesit, për të optimizuar përdorimin e kujtesës dhe hapësirën e ruajtjes.

Kushtet paraprake:

Përpara se të zhytemi në zbatimin, sigurohuni që të keni parakushtet e mëposhtme:

  • Një llogari AWS me qasje në shërbimin S3
  • Node.js dhe npm (Menaxheri i paketës së nyjeve) të instaluara në kompjuterin tuaj
  • Njohuri bazë të koncepteve JavaScript dhe AWS

Hapi 1: Konfigurimi i AWS dhe varësive:

Për të filluar, instaloni varësitë e nevojshme. Krijoni një projekt të ri Node.js dhe instaloni paketat e mëposhtme duke përdorur npm:

  • @aws-sdk/client-s3
  • @aws-sdk/lib-storage
  • @aws-sdk/s3-request-presigner
  • archiver

Për të konfiguruar kredencialet tona AWS, jepni konfigurimin e mëposhtëm ose në vetë skedarin ose në një skedar të veçantë config.js.

const AWS_CONFIG = {
  credentials: {
    accessKeyId: <aws_access_key_id>,
    secretAccessKey: <aws_secret_access_key>,
  },
  region: <aws_s3_region>,
}
const AWS_S3_BUCKET = <aws_s3_bucket>

Hapi 2: Transmetimi i të dhënave nga S3:

Fillojmë duke krijuar një funksion të quajtur getReadableStreamFromS3, i cili merr një çelës S3 si hyrje. Ky funksion përdor mjetin GetObjectCommand nga biblioteka @aws-sdk/client-s3 për të marrë skedarin nga S3 dhe e kthen skedarin si një transmetim të lexueshëm. Duke përdorur transmetimet, ne shmangim ruajtjen e të gjithë skedarit në memorie.

async function getReadableStreamFromS3(s3Key: string) {
  const client = new S3Client(AWS_CONFIG);
  const command = new GetObjectCommand({
    Bucket: AWS_S3_BUCKET,
    Key: s3Key,
  });
  const response = await client.send(command);
  return response.Body;
}

Hapi 3: Ngarkimi i të dhënave të postuara në S3:

Më pas, ne krijojmë një funksion të quajtur getWritableStreamFromS3, i cili merr një çelës destinacioni S3 për skedarin e zip si hyrje. Ky funksion përdor mjetin Upload nga @aws-sdk/lib-storagelibrary. Meqenëse funksioni Upload nuk ekspozon drejtpërdrejt një transmetim të shkrueshëm, ne përdorim një 'transmetim kalimtar' duke përdorur objektin PassThrough nga API-ja e transmetimeve Node.js. Ky objekt vepron si një përfaqësues për një transmetim të shkruajtshëm dhe na lejon të ngarkojmë të dhënat e grumbulluara në S3 në mënyrë efikase.

function getWritableStreamFromS3(zipFileS3Key: string) {
  let _passthrough = new PassThrough();
  const s3 = new S3(AWS_CONFIG);
  new Upload({
    client: s3,
    params: {
      Bucket: AWS_S3_BUCKET,
      Key: zipFileS3Key,
      Body: _passthrough,
    },
  }).done();
  return _passthrough;
}

Hapi 4: Gjenerimi dhe transmetimi i skedarëve zip në S3:

Në këtë hap, ne krijojmë një funksion të quajtur generateAndStreamZipfileToS3, i cili merr një listë të çelësave S3 (s3KeyList) dhe çelësin e destinacionit për skedarin zip të ngarkuar (zipFileS3Key). Brenda këtij funksioni, ne përdorim bibliotekën archiver për të krijuar një arkiv zip. Ne përsërisim përmes s3KeyList, marrim çdo skedar si një transmetim të lexueshëm duke përdorur getReadableStreamFromS3 dhe e shtojmë atë në arkivin zip. Më pas, marrim rrymën e shkruajtshme duke përdorur getWritableStreamFromS3 dhe dërgojmë arkivin zip në të. Së fundi, ne telefonojmë zip.finalize() për të filluar procesin e zipping.

async function generateAndStreamZipfileToS3(
  s3KeyList: [string],
  zipFileS3Key: string
) {
  try {
    let zip = archiver("zip");
    for (const s3Key of s3KeyList) {
      const s3ReadableStream = await getReadableStreamFromS3(s3Key);
      zip.append(<Readable>s3ReadableStream, { name: s3Key.split("/").pop()! });
    }
    const s3WritableStream = getWritableStreamFromS3(zipFileS3Key);
    zip.pipe(s3WritableStream);
    zip.finalize();
  } catch (error: any) {
    logger.error(`Error in generateAndStreamZipfileToS3 ::: ${error.message}`);
  }
}

Hapi 5: Shërbimi i skedarit S3 të Zipped me një URL të paracaktuar:

Për të siguruar akses të sigurt në skedarin e zip, ne mund të gjenerojmë një URL të caktuar me vlefshmëri të kufizuar. Në këtë hap opsional, ne krijojmë një funksion të quajtur generatePresignedURLforZip, i cili merr zipFileS3Key si hyrje. Duke përdorur mjetin GetObjectCommand nga @aws-sdk/s3-request-presignerlibrary, ne gjenerojmë një URL të caktuar që skadon pas 24 orësh. Kjo URL mund të ndahet me përdoruesit, duke i lejuar ata të shkarkojnë skedarin e zikuar brenda kornizës kohore të specifikuar.

export async function generatePresignedURLforZip(zipFileS3Key: string) {
  logger.info("Generating Presigned URL for the zip file.");
  const client = new S3Client(AWS_CONFIG);
  const command = new GetObjectCommand({
    Bucket: AWS_S3_BUCKET,
    Key: zipFileS3Key,
  });
  const signedUrl = await getSignedUrl(client, command, {
    expiresIn: 24 * 3600,
  });
  return signedUrl;
}

Përfundim:

Duke shfrytëzuar fuqinë e transmetimeve të lexueshme dhe të shkruajtshme në kombinim me bibliotekën e arkivimit, ne mund të zipjmë në mënyrë efikase skedarët e ruajtur në Amazon S3 në një mjedis pa server. Kjo qasje minimizon përdorimin e memories dhe kufizimet e ruajtjes, duke na mundësuar që të trajtojmë skedarë të mëdhenj pa i mbingarkuar burimet tona. Për më tepër, duke përdorur URL të paracaktuara, ne mund t'i ndajmë në mënyrë të sigurt skedarët e zikuar me përdoruesit për një kohëzgjatje të kufizuar. Herën tjetër që duhet t'u ofroni përdoruesve një mënyrë të përshtatshme për të shkarkuar skedarë të shumtë nga S3, merrni parasysh zbatimin e kësaj zgjidhjeje me Node.js.

Mos harroni të trajtoni gabimet dhe të përfshini trajtimin e duhur të gabimeve në zbatimin tuaj aktual. Gëzuar kodimin!

Referencat: