web-dev-qa-db-fra.com

Amazon S3 Modifier le nom de téléchargement du fichier

J'ai des fichiers stockés sur S3 avec un GUID comme nom de clé.

J'utilise une URL pré-signée pour télécharger selon S3 REST API

Je stocke le nom du fichier d'origine dans ma propre base de données. Lorsqu'un utilisateur clique pour télécharger un fichier à partir de mon application Web , je veux retourner son nom de fichier d'origine, mais actuellement tout ce qu'il obtient est un GUID . Comment puis-je atteindre cet objectif?

Mon application Web est dans Salesforce, je n'ai donc pas beaucoup de contrôle pour faire une réponse. Redirige tous les fichiers vers le serveur Web, puis renommez-le en raison des limitations du gouverneur.

Y a-t-il une redirection HTML, une méta-actualisation, Javascript que je peux utiliser? Existe-t-il un moyen de changer le nom du fichier de téléchargement pour S3 (la seule chose à laquelle je peux penser est de copier l'objet vers un nouveau nom, de le télécharger, puis de le supprimer).

Je veux éviter de créer un compartiment par utilisateur car nous aurons beaucoup d'utilisateurs et toujours aucune garantie que chaque fichier avec dans chaque compartiment aura un nom unique

D'autres solutions?

75
Daveo

Je suppose que votre croix a posté ces questions sur forum Amazon S , mais pour le bien des autres, j'aimerais poster la réponse ici:

S'il n'y a qu'un seul "nom de fichier utilisateur" pour chaque objet S3, vous pouvez définir l'en-tête Content-Disposition sur votre fichier s3 pour définir le nom de fichier à télécharger: Content-Disposition: attachment; filename = foo.bar

Par souci d'équité, je voudrais mentionner que ce n'était pas moi de fournir la bonne réponse sur le forum Amazon et tous les crédits devraient aller à Colin Rhodes ;-)

69
cloudberryman

Bien que la réponse acceptée soit correcte, je la trouve très abstraite et difficile à utiliser.

Voici un morceau de code node.js qui résout le problème indiqué. Je conseille de l'exécuter en tant qu'AWS Lambda pour générer une URL pré-signée.

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...]

}

Veuillez prendre note de l'attribut ResponseContentDisposition de l'objet params passé dans s3.getSignedUrl une fonction.

Plus d'informations sous la fonction getObject doc à http://docs.aws.Amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property

24
Pawel

Début janvier 2011, S3 a ajouté des remplacements d'en-tête de demande. Cette fonctionnalité vous permet de modifier "dynamiquement" l'en-tête Content-Disposition pour les demandes individuelles.

Voir le S3 documentation sur l'obtention d'objets pour plus de détails.

23
Uriah Carpenter

Pour Java AWS SDK ci-dessous, l'extrait de code devrait faire le travail:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);
1
Abhishek Basak

Avec C # utilisant 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);
0
hkutluay

Il ressemble à ceci: response_content_disposition n'est pas documenté dans la méthode presigned_url. C'est ce qui a fonctionné pour moi

    signer = Aws::S3::Presigner.new
    signer.presigned_url(:get_object, bucket: @bucket, key: filename, 
    response_content_disposition: "attachment; filename =#{new_name}")
0
Chris Mcdonald

J'ai le même problème, je l'ai résolu en définissant l'en-tête http "content-disposition" tout en soumettant le fichier à S3, la version du SDK est AWS SDK pour PHP 3.x. voici la doc http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

un morceau de mon code

    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
mok