Amazon S3 Change file download name

55,411

Solution 1

I guess your cross posted this questions to Amazon S3 forum, but for the sake of others I'd like to post the answer here:

If there is only ever one "user filename" for each S3 object, then you can set the Content-Disposition header on your s3 file to set the downloading filename:

Content-Disposition: attachment; filename="foo.bar"

For the sake of fairness I'd like to mention that it was not me to provide the right answer on Amazon forum and all credits should go to Colin Rhodes ;-)

Solution 2

While the accepted answer is correct I find it very abstract and hard to utilize.

Here is a piece of node.js code that solves the problem stated. I advise to execute it as the AWS Lambda to generate pre-signed 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...]

}

Please, take note of ResponseContentDisposition attribute of params object passed into s3.getSignedUrl function.

More information under getObject function doc at http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property

Solution 3

In early January 2011 S3 added request header overrides. This functionality allows you to 'dynamically' alter the Content-Disposition header for individual requests.

See the S3 documentation on getting objects for more details.

Solution 4

With C# using 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);

Solution 5

For Java AWS SDK below Code Snippet should do the job:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);
Share:
55,411
Daveo
Author by

Daveo

Updated on April 18, 2022

Comments

  • Daveo
    Daveo about 2 years

    I have files stored on S3 with a GUID as the key name.

    I am using a pre signed URL to download as per S3 REST API

    I store the original file name in my own Database. When a user clicks to download a file from my web application I want to return their original file name, but currently all they get is a GUID. How can I achieve this?

    My web app is in salesforce so I do not have much control to do response.redirects all download the file to the web server then rename it due to governor limitations.

    Is there some HTML redirect, meta refresh, Javascript I can use? Is there some way to change the download file name for S3 (the only thing I can think of is coping the object to a new name, downloading it, then deleting it).

    I want to avoid creating a bucket per user as we will have a lot of users and still no guarantee each file with in each bucket will have a unique name

    Any other solutions?

    • DeepSpace101
      DeepSpace101 about 11 years
      Another legit SO question that's closed as off-topic! The question and answers too have more votes than a vast majority of usual questions/answers...
    • Derek Litz
      Derek Litz over 10 years
      Yes, it's obviously more important that we try to organize things somewhat arbitrarily in the face of the fact it's not guaranteed to make sense in the future or even now. What happened when people just had fun asking and answering questions related to the software industry? Who actually finds the answer because of this organization? Who finds any organizational structure in software consistent and clearly defined across the industry? Without this clear definition that will last a significant amount of time organizing it is a fairly stupid waste of time...
    • Isaiah Turner
      Isaiah Turner almost 10 years
      I find this answer, I have no issue with this organization.
  • Daveo
    Daveo about 14 years
    yes thank you for reminding me. The other piece of vital information is when adding Content-Disposition it is cases-sensitive and does NOT need in x-amz prefix.
  • fabi
    fabi over 8 years
    Take a look at the answer below, since January 2011 it is also possible on a per GET request basis. So it's possible to have as many "user filenames" as you want.
  • nathancahill
    nathancahill over 8 years
    I needed to add quotes to the filename to get this to work, so my header was: Content-Disposition: attachment; filename="foo.bar"
  • Amir M
    Amir M almost 7 years
    In c#: request.ResponseHeaderOverrides.ContentDisposition = "attachment; filename=foo.bar";
  • Pawel
    Pawel about 6 years
    Maybe it's not obvious, I will try to explain better. The idea is that I keep list of names of uploaded files in database, and then when someone wants to download it I execute lambda with a originalFilename as parameter.
  • alaster
    alaster over 4 years
    You could override response headers on the fly: https://...example.txt?response-content-disposition=attachme‌​nt;filename=foo.bar
  • lazycipher
    lazycipher over 3 years
    @alaster did this work for you? I'm getting The request signature we calculated does not match the signature you provided. Check your key and signing method. When I remove this response-content-disposition=attachment;filename=foo.bar it downloads the file but with original name.
  • alaster
    alaster over 3 years
    @lazycipher worked for me without an error
  • Alexey Sh.
    Alexey Sh. about 3 years
    Header value cannot be represented using ISO-8859-1.
  • Alexey Sh.
    Alexey Sh. about 3 years
    the originalFilename should be encoded. I used encodeURIComponent to solve the error
  • Rich
    Rich over 2 years
    Thanks for this, I was able translate this to use in my VB.NET project as: request.ResponseHeaderOverrides.ContentDisposition = "attachment; filename=""my-new-filename-here.txt"""
  • Constantine Kurbatov
    Constantine Kurbatov over 2 years
    @alaster's recommendation has a note from Amazon's docs: You must sign the request, either using an Authorization header or a presigned URL, when using these parameters. They cannot be used with an unsigned (anonymous) request.