Amazon S3 Cambiar el nombre de descarga del archivo

102

Tengo archivos almacenados en S3 con un GUID como nombre de clave.

Estoy usando una URL firmada previamente para descargar según la API REST de S3

Guardo el nombre del archivo original en mi propia base de datos. Cuando un usuario hace clic para descargar un archivo de mi aplicación web, quiero devolver su nombre de archivo original, pero actualmente todo lo que obtiene es un GUID . ¿Cómo puedo conseguir esto?

Mi aplicación web está en Salesforce, por lo que no tengo mucho control para hacer response.redirects todos descargan el archivo al servidor web y luego le cambian el nombre debido a limitaciones del gobernador.

¿Hay alguna redirección de HTML, meta actualización, Javascript que pueda usar? ¿Hay alguna manera de cambiar el nombre del archivo de descarga para S3 (lo único que se me ocurre es cambiar el nombre del objeto, descargarlo y luego eliminarlo)?

Quiero evitar la creación de un depósito por usuario, ya que tendremos muchos usuarios y aún no hay garantía de que cada archivo en cada depósito tenga un nombre único.

¿Alguna otra solución?

Daveo
fuente
7
¡Otra pregunta SO legítima que está cerrada como fuera de tema! La pregunta y las respuestas también tienen más votos que la gran mayoría de las preguntas / respuestas habituales ...
DeepSpace101
Sí, obviamente es más importante que tratemos de organizar las cosas de forma un tanto arbitraria ante el hecho de que no está garantizado que tenga sentido en el futuro o incluso ahora. ¿Qué sucedió cuando la gente simplemente se divirtió haciendo y respondiendo preguntas relacionadas con la industria del software? ¿Quién encuentra realmente la respuesta gracias a esta organización? ¿Quién encuentra una estructura organizacional en software consistente y claramente definida en toda la industria? Sin esta definición clara que durará una cantidad significativa de tiempo, organizarlo es una pérdida de tiempo bastante estúpida ...
Derek Litz
1
Encuentro esta respuesta, no tengo ningún problema con esta organización.
Isaiah Turner

Respuestas:

83

Supongo que su cruz publicó estas preguntas en el foro de Amazon S3 , pero por el bien de los demás, me gustaría publicar la respuesta aquí:

Si solo hay un "nombre de archivo de usuario" para cada objeto S3, entonces puede configurar el encabezado Content-Disposition en su archivo s3 para configurar el nombre del archivo de descarga: Content-Disposition: adjunto; nombre de archivo = foo.bar

En aras de la justicia, me gustaría mencionar que no fui yo quien proporcionó la respuesta correcta en el foro de Amazon y que todos los créditos deben ir a Colin Rhodes ;-)

Cloudberryman
fuente
sí, gracias por recordármelo. La otra pieza de información vital es cuando se agrega Content-Disposition, se distingue entre mayúsculas y minúsculas y NO necesita el prefijo x-amz.
Daveo
3
Eche un vistazo a la respuesta a continuación, desde enero de 2011 también es posible por solicitud GET. Por tanto, es posible tener tantos "nombres de archivo de usuario" como desee.
fabi
2
Necesitaba agregar comillas al nombre del archivo para que esto funcionara, por lo que mi encabezado era: Content-Disposition: adjunto; filename = "foo.bar"
nathancahill
1
En c #: request.ResponseHeaderOverrides.ContentDisposition = "adjunto; nombre de archivo = foo.bar";
Amir M
2
Puede anular los encabezados de respuesta sobre la marcha:https://...example.txt?response-content-disposition=attachment;filename=foo.bar
desgracia,
46

Si bien la respuesta aceptada es correcta, la encuentro muy abstracta y difícil de utilizar.

Aquí hay un fragmento de código de node.js que resuelve el problema indicado. Aconsejo ejecutarlo como AWS Lambda para generar una URL firmada previamente.

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

}

Por favor, tome nota del ResponseContentDispositionatributo del paramsobjeto pasado a la s3.getSignedUrlfunción.

Más información en el documento de la función getObject en http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property

Pawel
fuente
Quizás no sea obvio, intentaré explicarlo mejor. La idea es que guardo una lista de nombres de archivos cargados en la base de datos, y luego, cuando alguien quiere descargarlo, ejecuto lambda con un originalFilenameparámetro como.
Pawel
27

A principios de enero de 2011, S3 agregó anulaciones de encabezado de solicitud. Esta funcionalidad le permite alterar 'dinámicamente' el encabezado Content-Disposition para solicitudes individuales.

Consulte la documentación de S3 sobre cómo obtener objetos para obtener más detalles.

Carpintero Uriah
fuente
3

Para Java, AWS SDK a continuación, el fragmento de código debería funcionar:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);
Abhishek Basak
fuente
3

Con C # usando 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
fuente
0

Tengo el mismo problema, lo resolví configurando el encabezado http "content-disposition" mientras enviaba el archivo a S3, la versión del SDK es AWS SDK para PHP 3.x. aquí está el documento http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

una parte de mi código

    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)
        {
            ...
        }
    }
mok
fuente
0

Parece que: response_content_disposition no está documentado en el método presigned_url. Esto es lo que funcionó para mi

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