AWS S3 Node.js — Установить содержимое-Расположение для объекта

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

#node.js #amazon-веб-сервисы #amazon-s3

Вопрос:

Я много искал в Интернете по этому поводу, но не смог найти решение. Я использую предварительно подписанные URL-адреса, чтобы предоставить пользователю возможность загружать файлы на S3. Но я хочу иметь возможность делать что-то вроде этого:

 export const getSignedUrlForUpload = async (destFilePath) => {
    const s3 = getS3Object({ signatureVersion: 'v4' });

    const params = {
        Bucket: process.env.AWS_BUCKET_NAME,
        Key: destFilePath,
        ContentDisposition: 'attachment; filename=data.jpg',
        ACL: "public-read",
    };

    return new Promise((resolve, reject) => {
        s3.getSignedUrl('putObject', params, (err, data) => {
            if (err) return reject(err);
            return resolve(data);
        });
    });
};
 

Для того, чтобы сделать файл загружаемым с моим желаемым именем.
Это не работает.
Как я могу этого добиться?

Комментарии:

1. Почему бы вам просто не использовать Key параметр?

2. Я использовал его раньше, но столкнулся с проблемой с именами файлов с символами на иврите и пробелами, поэтому я предпочитаю генерировать идентификатор для ключа, и когда клиент загружает файл, у него будет правильное имя файла.

Ответ №1:

Ваш код должен работать уже как есть, я пробовал с обычным putObject ( getSignedUrl поддерживает те же параметры), и вот результаты.

Я загружаю объект:

 const params = {
  Bucket: 'my_bucket',
  Key: 'MDSD.pdf', // This could be anything with standard chars
  Body: fileContent,
  ACL: 'public-read',
  ContentDisposition: 'attachment; filename=test.pdf',
};

s3.upload(params, function (err, data) {
  if (err) {
    throw err;
  }
  console.log(`File uploaded successfully. ${data.Location}`);
});
 

На консоли S3 это выглядит так:
скриншот консоли AWS S3 - раздел метаданных

Если мы проверим информацию об объекте через AWS CLI, это будет выглядеть так:

 aws s3api head-object --bucket my_bucket --key MDSD.pdf
// output
AcceptRanges: bytes
ContentDisposition: attachment; filename=test.pdf
ContentLength: 5067743
ContentType: application/pdf
ETag: '"xxxxxxxxxxxxxxxxxx"'
LastModified: '2020-11-26T15:59:02 00:00'
Metadata: {}
 

Если я попытаюсь загрузить файл с wget помощью, используя --content-disposition флаг, вы увидите, что предложенное имя файла соблюдается:

 wget https://my_bucket.s3.eu-central-1.amazonaws.com/MDSD.pdf --content-disposition
// output
--2020-11-26 17:00:32--  https://my_bucket.s3.eu-central-1.amazonaws.com/MDSD.pdf
Resolving my_bucket.s3.eu-central-1.amazonaws.com... 10.119.74.124
Connecting to my_bucket.s3.eu-central-1.amazonaws.com|10.119.74.124|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5067743 (4.8M) [application/pdf]
Saving to: 'test.pdf'

test.pdf            100%[===================>]   4.83M  8.85MB/s    in 0.5s    

2020-11-26 17:00:33 (8.85 MB/s) - 'test.pdf' saved [5067743/5067743]
 

Я также провел еще один тест, на этот раз используя именно ваш код, а затем попытался программно загрузить файл с помощью библиотеки axios:

 const getUrlAndUpload = async () => {
  // Get Url (your code)
  let presignedUrl = await getPresignedUrl();

  // Read content from the file
  const fileContent = fs.readFileSync('any_name.pdf');

  var options = {
    headers: {
      'Content-Disposition': 'attachment; filename=test.pdf',
      'x-amz-acl': 'public-read',
    },
  };

  let response;
  try {
    response = await axios.put(presignedUrl, fileContent, options);
  } catch (err) {
    console.log(err);
    process.exit(1);
  }
  console.log(response);
  process.exit(0);
};

console.log(getUrlAndUpload());
// {status: 200, statusText: 'OK', headers: {…}, config: {…}, request: ClientRequest, …}
 

Важная деталь (я также наткнулся на это во время тестирования) заключается в том, что при загрузке вам нужно всегда указывать те же параметры, которые вы подписываете добавить x-amz-acl тот, который в данном случае есть public-read . Если, например, вы добавляете Content-Type при подписании URL-адреса, вам также нужно будет указать Content-Type в заголовках запроса на загрузку.

Комментарии:

1. Таким образом, при добавлении ContentDisposition в параметры заголовок content-disposition добавляется в список X-Amz-SignedHeaders в подписанном URL. Но при попытке ПОМЕСТИТЬ объект из браузера я получаю 403 Forbidden в качестве ответа от s3.

2. Вы правы, я обновил ответ другим примером, чтобы показать, что вам нужно указать правильные заголовки в PUT запросе.