Amazon S3 Modifica il nome del download del file


102

Ho dei file memorizzati su S3 con un GUID come nome della chiave.

Sto utilizzando un URL pre-firmato per il download secondo l' API REST S3

Memorizzo il nome del file originale nel mio database. Quando un utente fa clic per scaricare un file dalla mia applicazione Web, desidero restituire il nome del file originale, ma attualmente tutto ciò che ottiene è un GUID . Come posso raggiungere questo obiettivo?

La mia app Web è in Salesforce, quindi non ho molto controllo per eseguire response. Reindirizza tutti i download del file sul server Web, quindi lo rinomina a causa delle limitazioni del governor.

C'è qualche reindirizzamento HTML, meta refresh, Javascript che posso usare? C'è un modo per cambiare il nome del file di download per S3 (l'unica cosa a cui posso pensare è copiare l'oggetto con un nuovo nome, scaricarlo e quindi eliminarlo).

Voglio evitare di creare un bucket per utente poiché avremo molti utenti e tuttavia non garantiamo che ogni file con in ciascun bucket avrà un nome univoco

Altre soluzioni?


7
Un'altra domanda SO legittima che è chiusa come fuori tema! Anche la domanda e le risposte hanno più voti della stragrande maggioranza delle solite domande / risposte ...
DeepSpace101

Sì, è ovviamente più importante che cerchiamo di organizzare le cose in modo un po 'arbitrario di fronte al fatto che non è garantito che abbia senso in futuro o anche adesso. Cosa è successo quando le persone si sono divertite a chiedere e rispondere a domande relative all'industria del software? Chi trova effettivamente la risposta grazie a questa organizzazione? Chi trova una struttura organizzativa nel software coerente e chiaramente definita in tutto il settore? Senza questa chiara definizione che durerà una notevole quantità di tempo organizzarsi è una perdita di tempo abbastanza stupida ...
Derek Litz

1
Trovo questa risposta, non ho problemi con questa organizzazione.
Isaiah Turner

Risposte:


83

Immagino che la tua croce abbia pubblicato queste domande sul forum di Amazon S3 , ma per il bene degli altri vorrei pubblicare la risposta qui:

Se è presente un solo "nome file utente" per ogni oggetto S3, è possibile impostare l'intestazione Content-Disposition sul file s3 per impostare il nome del file di download: Content-Disposition: attachment; nomefile = foo.bar

Per correttezza vorrei ricordare che non sono stato io a fornire la risposta giusta sul forum di Amazon e tutti i riconoscimenti dovrebbero andare a Colin Rhodes ;-)


si grazie per avermelo ricordato. L'altra informazione vitale è che quando si aggiunge Content-Disposition si fa distinzione tra maiuscole e minuscole e NON ha bisogno del prefisso x-amz.
Daveo

3
Dai un'occhiata alla risposta qui sotto, da gennaio 2011 è possibile anche su richiesta GET. Quindi è possibile avere tutti i "nomi di file utente" che desideri.
fabi

2
Avevo bisogno di aggiungere virgolette al nome del file per farlo funzionare, quindi la mia intestazione era: Content-Disposition: attachment; filename = "foo.bar"
nathancahill

1
In c #: request.ResponseHeaderOverrides.ContentDisposition = "attachment; filename = foo.bar";
Amir M

2
È possibile ignorare le intestazioni di risposta al volo:https://...example.txt?response-content-disposition=attachment;filename=foo.bar
alaster

46

Sebbene la risposta accettata sia corretta, la trovo molto astratta e difficile da utilizzare.

Ecco un pezzo di codice node.js che risolve il problema indicato. Consiglio di eseguirlo come AWS Lambda per generare URL pre-firmato.

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

}

Per favore, prendi nota ResponseContentDispositiondell'attributo paramsdell'oggetto passato alla s3.getSignedUrlfunzione.

Maggiori informazioni nel documento della funzione getObject su http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property


Forse non è scontato, cercherò di spiegare meglio. L'idea è che tengo l'elenco dei nomi dei file caricati nel database, quindi quando qualcuno vuole scaricarlo eseguo lambda con un originalFilenameparametro as.
Pawel

27

All'inizio di gennaio 2011 S3 ha aggiunto le sostituzioni dell'intestazione della richiesta. Questa funzionalità consente di modificare "dinamicamente" l'intestazione Content-Disposition per singole richieste.

Vedere la documentazione di S3 su come ottenere oggetti per maggiori dettagli.


3

Per Java AWS SDK sotto lo snippet di codice dovrebbe fare il lavoro:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);

3

Con C # utilizzando 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

Ho lo stesso problema, l'ho risolto impostando l'intestazione http "content-disposition" durante l'invio del file a S3, la versione dell'SDK è AWS SDK per PHP 3.x. ecco il documento http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

un pezzo del mio codice

    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

Sembra che: response_content_disposition non sia documentato nel metodo presigned_url. Questo è ciò che ha funzionato per me

    signer = Aws::S3::Presigner.new
    signer.presigned_url(:get_object, bucket: @bucket, key: filename, 
    response_content_disposition: "attachment; filename =#{new_name}")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.