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?


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 ;-)


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


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


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);

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);

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

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}")
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.