В Node.js Создайте поток чтения из объекта S3 или веб-URL и передайте поток чтения нескольким каналам

#node.js #amazon-web-services #amazon-s3

Вопрос:

В лямбда-функции на основе Node.js12.x я пытаюсь

  1. Загрузить объект из S3
  2. Загрузите файл из Интернета, если объект не существует в S3
  3. Передайте загруженные данные независимо от того, как они поступили в несколько потоков записи

Я попытался следовать

 var request = require('request');

const readStream = ({ Bucket, Key }) => {

  s3.getObjectMetadata({ Bucket, Key })
    .promise().then(() => {
      return s3.getObject().createReadStream();
    })
    .catch(error => {
      if (error.statusCode === 404) {
        return request.get('http://example.com/'   Key);
      }
    });
};

readStream({ ... })
  .pipe(sharp().resize(w, h).toFormat('png'))
  .pipe(writeStream);
 

Выше работает, если объект доступен в s3, но блок catch не работает.

Мне нужно await или нужно обещание request.get ?

Я также пытался следовать за ним, но безуспешно

 http.get('http://example.com/'   Key, function(response) { 
    return response;
});
 

Ответ №1:

Сначала нам нужно создать обещание, которое проверяет, существует ли объект в корзине

 const isObjectExists = (params) => {
  return s3.headObject(params)
           .promise()
           .then(
             () => true,
             (error) => {
               if (err.statusCode === 404) {
                 return false;
               }
               throw error;
             }
           )}

const awsParams = { Bucket: ..., Key: s3ObjectKey };
const exists = await isObjectExists(awsParams);
 

Затем нам нужно создать поток чтения либо из s3, либо из веб-URL.

Используя устаревший request пакет, так как я не могу заставить вещи работать с помощью http .

 let readStream = null;
if (exists) {
    readStream = s3.getObject(awsParams).createReadStream();
} else {
    readStream = request.get('http://example.com/'   s3ObjectKey);
}
 

Передайте только что созданное readStream в процесс и, наконец, в поток загрузки

 const pass = new PassThrough();

readStream.
  .pipe(sharp().resize(w, h).toFormat('png'))
  .pipe(s3.upload({
    Body: pass,
    Bucket,
    ContentType: 'image/png',
    s3ObjectKey   '-resized'
  }).promise());

const uploadedData = await pass;
 

Добавьте несколько предварительных условий

 import awS3 from 'aws-sdk/clients/s3';
import { PassThrough } from 'stream'
import * as request from 'request';

const s3 = new awS3({signatureVersion: 'v4'});