#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 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
запросе.