Amazon S3 Change file download name
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 gu开发者_如何学Carantee each file with in each bucket will have a unique name
Any other solutions?
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 ;-)
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
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.
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);
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);
It looks like :response_content_disposition is undocumented in the presigned_url method. This is what worked for me
signer = Aws::S3::Presigner.new
signer.presigned_url(:get_object, bucket: @bucket, key: filename,
response_content_disposition: "attachment; filename =#{new_name}")
Using python and boto v2:
conn = boto.connect_s3(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
host=settings.AWS_S3_HOST,
)
b = conn.get_bucket(BUCKET_NAME)
key = b.get_key(path)
url = key.generate_url(
expires_in=60 * 60 * 10, # expiry time is in seconds
response_headers={
"response-content-disposition": "attachment; filename=foo.bar"
},
)
I have the same issue, I solved it by set http header "content-disposition" while submit the file to S3, the SDK version is AWS SDK for PHP 3.x. here is the doc http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject
a piece of my 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)
{
...
}
}
I spent a few hours to find this solution.
const { CloudFront } = require("aws-sdk");
const url = require("url");
const generateSingedCloudfrontUrl = (path) => {
const cloudfrontAccessKeyId = process.env.CF_ACCESS_KEY;
const cloudFrontPrivateKey = process.env.CF_PRIVATE_KEY;
const formattedKey = `${"-----BEGIN RSA PRIVATE KEY-----"}\n${cloudFrontPrivateKey}\n${"-----END RSA PRIVATE KEY-----"}`;
const signer = new CloudFront.Signer(cloudfrontAccessKeyId, formattedKey);
// 12 hours
const EXPIRY_TIME = 43200000;
const domain = process.env.CF_DOMAIN;
const signedUrl = signer.getSignedUrl({
url: url.format(`https://${domain}/${path}`),
expires: Math.floor((Date.now() + EXPIRY_TIME) / 1000),
});
return signedUrl;
};
const fileName = "myFile.png";
const result = generateSingedCloudfrontUrl(
`originals/orgs/originals/MSP/1539087e-02b7-414f-abc8-3542ee0c8420/1644588362499/Screenshot from 2022-02-09 16-29-04..png?response-content-disposition=${encodeURIComponent(
`attachment; filename=${fileName}`
)
});
Faced similar issue. Need to generate pre-signed url to download pdf from s3 but with different name other that what present in s3 bucket. This got resolved by using :-
Using Python boto3
file_download_url = client.generate_presigned_url(
ClientMethod = "get_object",
ExpiresIn = 3600,
Params = {
"Bucket": "s3_bucket_name",
"Key": "s3_key",
"ResponseContentDisposition": "attachment; filename=file_name.pdf",
"ResponseContentType" : "application/pdf"
}
)
Reference :- https://github.com/boto/boto3/issues/356
精彩评论