Amazon S3 Thay đổi tên tải xuống tệp


102

Tôi có các tệp được lưu trữ trên S3 với GUID làm tên khóa.

Tôi đang sử dụng URL được ký trước để tải xuống theo API REST của S3

Tôi lưu tên tệp gốc trong Cơ sở dữ liệu của riêng tôi. Khi người dùng nhấp để tải xuống tệp từ ứng dụng web của tôi, tôi muốn trả lại tên tệp ban đầu của họ, nhưng hiện tại tất cả những gì họ nhận được là GUID . Làm thế nào tôi có thể đạt được điều này?

Ứng dụng web của tôi nằm trong lực lượng bán hàng nên tôi không có nhiều quyền kiểm soát để thực hiện response. Chuyển hướng tất cả tải tệp xuống máy chủ web sau đó đổi tên tệp do giới hạn của thống đốc.

Có một số chuyển hướng HTML, làm mới meta, Javascript mà tôi có thể sử dụng không? Có một số cách để thay đổi tên tệp tải xuống cho S3 (điều duy nhất tôi có thể nghĩ là chuyển đối tượng sang một tên mới, tải xuống, sau đó xóa nó).

Tôi muốn tránh tạo nhóm cho mỗi người dùng vì chúng tôi sẽ có rất nhiều người dùng và vẫn không đảm bảo mỗi tệp trong mỗi nhóm sẽ có một tên duy nhất

Bất kỳ giải pháp nào khác?


7
Một câu hỏi SO hợp pháp khác bị đóng lại là lạc đề! Các câu hỏi và câu trả lời cũng có nhiều phiếu hơn một phần lớn các câu hỏi thông thường / câu trả lời ...
DeepSpace101

Vâng, rõ ràng điều quan trọng hơn là chúng ta cố gắng sắp xếp mọi thứ một cách tùy tiện khi đối mặt với thực tế là nó không được đảm bảo sẽ có ý nghĩa trong tương lai hoặc thậm chí ngay bây giờ. Điều gì đã xảy ra khi mọi người chỉ vui vẻ hỏi và trả lời các câu hỏi liên quan đến ngành phần mềm? Ai thực sự tìm ra câu trả lời nhờ tổ chức này? Ai tìm thấy bất kỳ cấu trúc tổ chức nào trong phần mềm nhất quán và được xác định rõ ràng trong toàn ngành? Nếu không có định nghĩa này rõ ràng là sẽ kéo dài một số lượng đáng kể thời gian tổ chức đó là một sự lãng phí khá ngu ngốc của thời gian ...
Derek Litz

1
Tôi tìm thấy câu trả lời này, tôi không có vấn đề gì với tổ chức này.
Isaiah Turner

Câu trả lời:


83

Tôi đoán bạn đã đăng câu hỏi này lên diễn đàn Amazon S3 , nhưng vì lợi ích của những người khác, tôi muốn đăng câu trả lời ở đây:

Nếu chỉ có một "tên tệp người dùng" cho mỗi đối tượng S3, thì bạn có thể đặt tiêu đề Nội dung-Bố trí trên tệp s3 của mình để đặt tên tệp tải xuống: Nội dung-Bố trí: tệp đính kèm; filename = foo.bar

Vì lý do công bằng, tôi muốn đề cập rằng không phải tôi đưa ra câu trả lời đúng trên diễn đàn Amazon và tất cả các khoản tín dụng sẽ được chuyển đến Colin Rhodes ;-)


vâng, cảm ơn bạn đã nhắc nhở tôi. Một thông tin quan trọng khác là khi thêm Nội dung-Bố trí, nó phân biệt chữ hoa chữ thường và KHÔNG cần tiền tố x-amz.
Daveo

3
Hãy xem câu trả lời bên dưới, kể từ tháng 1 năm 2011, nó cũng có thể được thực hiện trên cơ sở yêu cầu GET. Vì vậy, bạn có thể có nhiều "tên tệp người dùng" như bạn muốn.
fabi

2
Tôi cần thêm dấu ngoặc kép vào tên tệp để tên tệp này hoạt động, vì vậy tiêu đề của tôi là: Nội dung-Bố trí: tệp đính kèm; filename = "foo.bar"
nathancahill

1
Trong c #: request.ResponseHeaderOverrides.ContentDisposition = "file đính kèm; filename = foo.bar";
Amir M

2
Bạn có thể ghi đè các tiêu đề phản hồi ngay lập tức:https://...example.txt?response-content-disposition=attachment;filename=foo.bar
alaster

46

Mặc dù câu trả lời được chấp nhận là đúng, tôi thấy nó rất trừu tượng và khó sử dụng.

Đây là một đoạn mã node.js giải quyết vấn đề đã nêu. Tôi khuyên bạn nên thực thi nó dưới dạng AWS Lambda để tạo Url được ký trước.

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

}

Hãy lưu ý đến ResponseContentDispositionthuộc tính của paramsđối tượng được truyền vào s3.getSignedUrlhàm.

Thông tin thêm trong tài liệu hàm getObject tại http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property


Có lẽ nó không rõ ràng, tôi sẽ cố gắng giải thích tốt hơn. Ý tưởng là tôi giữ danh sách tên của các tệp đã tải lên trong cơ sở dữ liệu và sau đó khi ai đó muốn tải xuống, tôi thực thi lambda với originalFilenametham số as.
Pawel


3

Đối với Java AWS SDK bên dưới Đoạn mã sẽ thực hiện công việc:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);

3

Với C # bằng 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

Tôi gặp vấn đề tương tự, tôi đã giải quyết nó bằng cách đặt tiêu đề http "content-disposition" trong khi gửi tệp tới S3, phiên bản SDK là AWS SDK cho PHP 3.x. đây là tài liệu http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

một đoạn mã của tôi

    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

Có vẻ như: response_content_disposition không có tài liệu trong phương thức presigned_url. Đây là những gì làm việc cho tôi

    signer = Aws::S3::Presigner.new
    signer.presigned_url(:get_object, bucket: @bucket, key: filename, 
    response_content_disposition: "attachment; filename =#{new_name}")
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.