Node.js AWS Lambda + Archiver lib - 创建 zip 文件时出错

Node.js AWS Lambda + Archiver lib - Error in zip file creation

各位,

我在 Node.js 中编写了一个 lambda,它获取一个文件夹并将其内容压缩。 为此,我使用了 Archiver 库:Archiver

以下是我创建文件的代码:

const zipFilePath = '/tmp/' + 'filename' + '.zip'
const output = fs.createWriteStream(zipFilePath);

const archive = archiver('zip', {
    zlib: { level: 9 }
});

output.on('close', function () {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.on('error', function(err){
    throw err;
});

await archive.pipe(output);
await archive.directory(destFolder, false);
await archive.finalize();

要写入文件,我使用 lambda 的 /tmp 文件夹,这是唯一具有写入权限的文件夹。

流程如下:

  1. 我得到文件夹的路径
  2. 压缩内容并将其保存在文件夹 destFolder

文件随后保存在 S3 存储桶中:

const file = await fs.readFileSync(filePath)
const params = {
    Bucket: bucketName,
    Key: fileName,
    Body: file
};
const res = await s3.upload(params).promise()
return res.Location

zip 文件生成了,问题是我下载的时候它已经损坏了。我试着用在线压缩文件分析器(this)分析它,分析结果如下:

Type = zip
ERRORS:
Unexpected end of archive
WARNINGS:
There are data after the end of archive
Physical Size = 118916
Tail Size = 19
Characteristics = Local

并且分析器显示文件都存在于 .zip 中(我可以看到它们的名称)。

最奇怪的是,如果我在 .tar

中创建文件(同样使用相同的库)而不是 .zip
const archive = archiver('tar', {
    zlib: { level: 9 }
});

文件生成正确,我可以将其解压为存档。基本上,就好像 .zip 格式本身有问题。

有没有人有过类似的经历?你能帮我找到解决办法吗?我需要创建 .zip 格式的文件。 谢谢。

问题是您无法正确压缩文件,这可能由许多问题引起,包括:

  • 您不是在等待文件被处理,您需要使用 .close() 事件来执行此操作。
  • 您没有发送正确的文件路径或目录以进行压缩,通常您上传的文件与项目根目录中的 lambda 文件一起保留在 Lambda 目录系统上的 /var/task/ , 所以要发送正确的文件使用 __dirname + '/file.name'
  • 您没有正确附加文件,如果您发送的文件正确,请检查 .file().append() 方法

如果您有以下 Lambda 结构:

~/my-function
├── index.js
└── node_modules
├── package.json
├── package-lock.json
├── test.txt //file to be sent zipped on s3

以下示例适合您:

const archiver = require('archiver')
const fs = require('fs')
const AWS = require('aws-sdk');
const s3 = new AWS.S3({apiVersion: '2006-03-01'});


const sendToS3 = async (filePath) => {
    const bucketName = "bucket_name";
    const fileName = "zipped.zip"
    const file = await fs.readFileSync(filePath)
    const params = {
        Bucket: bucketName,
        Key: fileName,
        Body: file
    };
    const res = await s3.upload(params).promise()
    return res.Location
}

exports.handler = async event => {
  return new Promise((resolve, reject) => {
    const zippedPathName = '/tmp/example.zip';
    const output = fs.createWriteStream(zippedPathName);
    const fileToBeZipped = __dirname + '/test.txt';
    const zip = archiver('zip')

    zip
      .append(fs.createReadStream(fileToBeZipped), { name: 'test.txt' })
      .pipe(output)

    zip.finalize()

    output.on('close', (result => {
        sendToS3(zippedPathName).then(result => {
            resolve(result)
        })
    }))
  })
}