Amazon S3 Изменить имя загрузки файла

102

У меня есть файлы, хранящиеся на S3 с идентификатором GUID в качестве имени ключа.

Я использую предварительно подписанный URL-адрес для загрузки в соответствии с S3 REST API

Я сохраняю исходное имя файла в моей базе данных. Когда пользователь щелкает, чтобы загрузить файл из моего веб-приложения, я хочу вернуть его исходное имя файла, но в настоящее время все, что они получают, - это GUID . Как я могу этого добиться?

Мое веб-приложение находится в отделе продаж, поэтому у меня нет особого контроля над ответом. Перенаправляет все загрузки файла на веб-сервер, а затем переименовывает его из-за ограничений регулятора.

Есть ли перенаправление HTML, мета-обновление, Javascript, которые я могу использовать? Есть ли способ изменить имя файла загрузки для S3 (единственное, что я могу придумать, это скопировать объект под новое имя, загрузить его, а затем удалить).

Я хочу избежать создания корзины для каждого пользователя, так как у нас будет много пользователей, и все еще нет гарантии, что каждый файл в каждой корзине будет иметь уникальное имя.

Какие-нибудь другие решения?

Давео
источник
7
Еще один законный вопрос SO, который закрыт как не по теме! Вопросы и ответы также
набирают
Да, очевидно, более важно, чтобы мы пытались организовать вещи несколько произвольно, учитывая тот факт, что это не гарантирует смысла в будущем или даже сейчас. Что произошло, когда люди просто весело задавали вопросы, связанные с индустрией программного обеспечения, и отвечая на них? Кто на самом деле находит ответ благодаря этой организации? Кто считает, что какая-либо организационная структура программного обеспечения согласована и четко определена в отрасли? Без этого четкого определения, на организацию которого уйдет значительное количество времени, это довольно глупая трата времени ...
Дерек Литц
1
Я нашел такой ответ, у меня нет проблем с этой организацией.
Исайя Тернер

Ответы:

83

Думаю, ваш кросс разместил этот вопрос на форуме Amazon S3 , но ради других я хотел бы разместить ответ здесь:

Если существует только одно «имя файла пользователя» для каждого объекта S3, то вы можете установить заголовок Content-Disposition в вашем файле s3, чтобы установить имя файла загрузки: Content-Disposition: attachment; filename = foo.bar

Честно говоря, я хотел бы упомянуть, что не я давал правильный ответ на форуме Amazon, и все кредиты должны быть отданы Колину Роудсу ;-)

морошка
источник
да, спасибо, что напомнили мне. Другая важная информация - при добавлении Content-Disposition она чувствительна к регистру и НЕ нуждается в префиксе x-amz.
Давео,
3
Взгляните на ответ ниже, с января 2011 года это также возможно для каждого запроса GET. Таким образом, можно иметь сколько угодно «имен файлов пользователей».
Fabi
2
Мне нужно было добавить кавычки к имени файла, чтобы заставить это работать, поэтому мой заголовок был: Content-Disposition: attachment; filename = "foo.bar"
Натанкахилл
1
В C #: request.ResponseHeaderOverrides.ContentDisposition = "attachment; filename = foo.bar";
Amir M
2
Вы можете переопределить заголовки ответов на лету:https://...example.txt?response-content-disposition=attachment;filename=foo.bar
alaster
46

Хотя принятый ответ верен, я считаю его очень абстрактным и трудным для использования.

Вот фрагмент кода node.js, который решает заявленную проблему. Я советую выполнить его как AWS Lambda для создания предварительно подписанного URL-адреса.

var AWS = require('aws-sdk');
var s3 = new AWS.S3({
    signatureVersion: 'v4'
});
const s3Url = process.env.BUCKET;

module.exports.main = (event, context, callback) => {
var s3key = event.s3key
var originalFilename = event.originalFilename

var url = s3.getSignedUrl('getObject', {
        Bucket: s3Url,
        Key: s3key,
        Expires: 600,
        ResponseContentDisposition: 'attachment; filename ="' + originalFilename + '"'
    });

[... rest of Lambda stuff...]

}

Обратите внимание на ResponseContentDispositionатрибут paramsобъекта, переданного в s3.getSignedUrlфункцию.

Дополнительная информация в документе функции getObject по адресу http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property.

Павел
источник
Может это не очевидно, попробую пояснить получше. Идея состоит в том, что я храню список имен загруженных файлов в базе данных, а затем, когда кто-то хочет его загрузить, я выполняю лямбду с originalFilenameпараметром as.
Павел
27

В начале января 2011 года S3 добавил переопределения заголовка запроса. Эта функция позволяет вам «динамически» изменять заголовок Content-Disposition для отдельных запросов.

См. Дополнительную информацию в документации S3 по получению объектов .

Юрай Карпентер
источник
3

Для Java AWS SDK, приведенный ниже, должен работать фрагмент кода:

GeneratePresignedUrlRequest generatePresignedUrlRequest = 
                new GeneratePresignedUrlRequest(s3Bucket, objectKey)
                .withMethod(HttpMethod.GET)
                .withExpiration(getExpiration());

ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
responseHeaders.setContentDisposition("attachment; filename =\"" + fileName + "\"");

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);
Абхишек Башак
источник
3

С C # с использованием AWSSDK,

GetPreSignedUrlRequest request = new GetPreSignedUrlRequest
{
    BucketName = BucketName,
    Key = Key,
    Expires = DateTime.Now.AddMinutes(25) 
};

request.ResponseHeaderOverrides.ContentDisposition = $"attachment; filename={FileName}";

var url = s3Client.GetPreSignedURL(request);
Hkutluay
источник
0

У меня такая же проблема, я решил ее, установив http-заголовок «content-disposition» при отправке файла на S3, версия SDK - это AWS SDK для PHP 3.x. вот документ http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

часть моего кода

    public function __construct($config) 
    {
        $this->handle = new S3Client([
            'credentials' => array(
                'key' => $config['key'],
                'secret' => $config['secret'],
            ),
            ...
        ]);

        ...
    }

    public function putObject($bucket, $object_name, $source_file, $content_type = false, $acl = 'public-read', $filename = '')
    {
        try {
            $params = [
                'Bucket'      => $bucket,
                'Key'         => $object_name,
                'SourceFile'  => $source_file,
                'ACL'         => $acl,
            ];

            if ($content_type) $params['ContentType'] = $content_type;
            if ($filename) $params['ContentDisposition'] = 'attachment; filename="' . $filename . '"';

            $result = $this->handle->putObject($params);

            ...
        }
        catch(Exception $e)
        {
            ...
        }
    }
мок
источник
0

Это выглядит так: response_content_disposition недокументирован в методе presigned_url. Это то, что сработало для меня

    signer = Aws::S3::Presigner.new
    signer.presigned_url(:get_object, bucket: @bucket, key: filename, 
    response_content_disposition: "attachment; filename =#{new_name}")
Крис Макдональд
источник