在 NodeJS 中,如何从 S3 下载文件

In NodeJS, how to download files from S3

在 ExpressJS 中,我想下载之前上传到 Amazon S3 存储桶的文件。

这是我当前的路线:

const express = require('express');
const AWS = require('aws-sdk');
const mammoth = require('mammoth');
const fs = require('fs').promises
const path = require('path')
const router = express.Router();

router.put('/:id/download', async (req, res, next) => {
  console.log('hitting download route')

  var id = req.params.id;
  let upload = await Upload.query().findById( id ).eager('user');

  console.log("file to download is: ", upload.name)

  AWS.config.update({
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  });

  const s3 = new AWS.S3();


  // var fileStream = fs.createWriteStream('/tmp/file.docx');
  // var s3Stream = s3.getObject(params).createReadStream();

  const downloadFromS3 = async () => {
    const params = {
      Bucket: process.env.AWS_BUCKET, 
      Key: upload.file_url.split("com/").reverse()[0]
    };
    const { Body } = await s3.getObject(params).promise()
    await fs.writeFile(`${ __dirname }/download.docx`, Body)

    return Body
  }


  // mammoth.convertToHtml({ path: '/Users/dariusgoore/Downloads/1585930968750.docx' })
  //   .then(async function(result) {
  //     await Upload.query().findById( id )
  //       .patch({
  //          html: result.value,
  //          conversion_messages: result.messages
  //       })  
  //     res.json(result);
  //   })

    // .done();

  res.send(downloadFromS3)
});

我没有收到任何错误,但是文件没有创建,或者如果我手动创建文件,它仍然是空的。

如果我没理解错的话,问题是你不是在等待文件写入本地文件系统,而是通过 express 在响应中返回它。

试试这个代码。

const express = require('express')
const AWS = require('aws-sdk')
const mammoth = require('mammoth')

const fs = require('fs').promises
const path = require('path')

const router = express.Router()

const s3 = new AWS.S3()

AWS.config.update({
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
})

const downloadFromS3 = async (key, location) => {
    const params = {
        Bucket: process.env.AWS_BUCKET,
        Key: key,
    }

    const { Body } = await s3.getObject(params).promise()
    await fs.writeFile(location, Body)

    return true
}

router.put('/:id/download', async (req, res, next) => {
    console.log('hitting download route')

    const upload = await Upload.query()
        .findById(req.params.id)
        .eager('user')

    console.log('file to download is: ', upload.name)

    const key = upload.file_url.split('com/').reverse()[0]

    const location = `${__dirname}/${key}.docx`

    await downloadFromS3(key, location)

    res.send({ key, location })
})

import { S3 } from 'aws-sdk';
import fs from 'fs';

export default class S3Service {
    s3: S3;
    constructor() {
        this.s3 = new S3({
            apiVersion: *****,
            region: ********
        });
    }
    
    //Download File
    async download(bucketName: string, keyName: string, localDest?: string): Promise<any> {
        if (typeof localDest == 'undefined') {
            localDest = keyName;
        }
        const params = {
            Bucket: bucketName,
            Key: keyName
        };
        console.log("params: ", params);

        let writeStream = fs.createWriteStream(localDest);

        return new Promise<any>((resolve, reject) => {
            const readStream = this.s3.getObject(params).createReadStream();

            // Error handling in read stream
            readStream.on("error", (e) => {
                console.error(e);
                reject(e);
            });

            // Resolve only if we are done writing
            writeStream.once('finish', () => {
                resolve(keyName);
            });

            // pipe will automatically finish the write stream once done
            readStream.pipe(writeStream);
        });
     }
  }