Estoy tratando de crear una función lambda para leer un archivo zip de s3 y servirlo. Pero después de descargar este archivo en el navegador, no puedo descomprimirlo y aparece el error "No se puede extraer, está en un formato no compatible". ¿Qué puede ser un problema?
const file = await s3.getObject({ Bucket: 'mybucket', Key: `file.zip` }).promise(); return { statusCode: 200, isBase64Encoded: true, body: Buffer.from(file.Body).toString('base64'), headers: { 'Content-Type': 'application/zip', 'Content-Disposition': `attachment; filename="file.zip"`, }, }Su file.Body ya debería ser un Buffer, por lo que Buffer.from(file.Body) debería ser innecesario pero inofensivo.
Creo que tu problema es que estás haciendo toString('base64') allí. La documentación dice:
Si el cuerpo es un blob binario, puede codificarlo como una cadena codificada en Base64 estableciendo isBase64Encoded en verdadero y configurando / como tipo de medio binario.
Esto me hace creer que en realidad significa que AWS convertirá automáticamente su cuerpo (no base64) en base64 en el cuerpo de respuesta. Si ese es el caso, debido a que usted hace .toString('base64') , su cuerpo se basará en 64 dos veces. Puede des-base64 su file.zip resultante y ver qué da.
La solución para mí fue configurar el encabezado de respuesta 'Content-Encoding': 'base64'.
puedes seguir este código a continuación
"use strict"; const AWS = require("aws-sdk"); const awsOptions = { region: "us-east-1", httpOptions: { timeout: 300000 // Matching Lambda function timeout } }; const s3 = new AWS.S3(awsOptions); const archiver = require("archiver"); const stream = require("stream"); const request = require("request"); const streamTo = (bucket, key) => { var passthrough = new stream.PassThrough(); s3.upload( { Bucket: bucket, Key: key, Body: passthrough, ContentType: "application/zip", ServerSideEncryption: "AES256" }, (err, data) => { if (err) throw err; } ); return passthrough; }; // Kudos to this person on GitHub for this getStream solution // https://github.com/aws/aws-sdk-js/issues/2087#issuecomment-474722151 const getStream = (bucket, key) => { let streamCreated = false; const passThroughStream = new stream.PassThrough(); passThroughStream.on("newListener", event => { if (!streamCreated && event == "data") { const s3Stream = s3 .getObject({ Bucket: bucket, Key: key }) .createReadStream(); s3Stream .on("error", err => passThroughStream.emit("error", err)) .pipe(passThroughStream); streamCreated = true; } }); return passThroughStream; }; exports.handler = async (event, context, callback) => { var bucket = event["bucket"]; var destinationKey = event["destination_key"]; var files = event["files"]; await new Promise(async (resolve, reject) => { var zipStream = streamTo(bucket, destinationKey); zipStream.on("close", resolve); zipStream.on("end", resolve); zipStream.on("error", reject); var archive = archiver("zip"); archive.on("error", err => { throw new Error(err); }); archive.pipe(zipStream); for (const file of files) { if (file["type"] == "file") { archive.append(getStream(bucket, file["uri"]), { name: file["filename"] }); } else if (file["type"] == "url") { archive.append(request(file["uri"]), { name: file["filename"] }); } } archive.finalize(); }).catch(err => { throw new Error(err); }); callback(null, { statusCode: 200, body: { final_destination: destinationKey } }); };