Amazon S3 เปลี่ยนชื่อดาวน์โหลดไฟล์


103

ฉันมีไฟล์ที่เก็บไว้ใน S3 โดยมี GUID เป็นชื่อคีย์

ฉันใช้ URL ที่ลงนามล่วงหน้าเพื่อดาวน์โหลดตามS3 REST API

ฉันเก็บชื่อไฟล์ต้นฉบับไว้ในฐานข้อมูลของฉันเอง เมื่อผู้ใช้คลิกเพื่อดาวน์โหลดไฟล์จากเว็บแอปพลิเคชันของฉันฉันต้องการที่จะกลับมาชื่อไฟล์ที่เดิม แต่ขณะนี้สิ่งที่พวกเขาได้รับคือ GUID ฉันจะบรรลุเป้าหมายนี้ได้อย่างไร?

แอปพลิเคชันเว็บของฉันอยู่ใน Salesforce ดังนั้นฉันจึงไม่สามารถควบคุมการตอบสนองได้มากนักเปลี่ยนเส้นทางทั้งหมดดาวน์โหลดไฟล์ไปยังเว็บเซิร์ฟเวอร์จากนั้นเปลี่ยนชื่อเนื่องจากข้อ จำกัด ของ Governor

มีการเปลี่ยนเส้นทาง HTML, การรีเฟรชเมตา, Javascript ที่ฉันสามารถใช้ได้หรือไม่? มีวิธีใดบ้างในการเปลี่ยนชื่อไฟล์ดาวน์โหลดสำหรับ S3 (สิ่งเดียวที่ฉันคิดได้คือจัดการกับวัตถุเป็นชื่อใหม่ดาวน์โหลดแล้วลบออก)

ฉันต้องการหลีกเลี่ยงการสร้างที่เก็บข้อมูลต่อผู้ใช้เนื่องจากเราจะมีผู้ใช้จำนวนมากและยังไม่รับประกันว่าแต่ละไฟล์ในที่เก็บข้อมูลแต่ละไฟล์จะมีชื่อที่ไม่ซ้ำกัน

วิธีแก้ปัญหาอื่น ๆ ?


7
อีกคำถาม SO ที่ถูกต้องที่ปิดเป็นหัวข้อ! คำถามและคำตอบก็มีคะแนนโหวตมากกว่าคำถาม / คำตอบปกติส่วนใหญ่ ...
DeepSpace101

ใช่เห็นได้ชัดว่าสำคัญกว่าที่เราพยายามจัดระเบียบสิ่งต่างๆตามอำเภอใจเมื่อเผชิญกับความจริงที่ว่ามันไม่รับประกันว่าจะสมเหตุสมผลในอนาคตหรือแม้แต่ตอนนี้ เกิดอะไรขึ้นเมื่อผู้คนสนุกกับการถามและตอบคำถามที่เกี่ยวข้องกับอุตสาหกรรมซอฟต์แวร์ ใครหาคำตอบได้จริงเพราะองค์กรนี้ ใครพบว่าโครงสร้างองค์กรใดในซอฟต์แวร์สอดคล้องและกำหนดไว้อย่างชัดเจนทั่วทั้งอุตสาหกรรม หากไม่มีคำจำกัดความที่ชัดเจนนี้จะใช้เวลาส่วนใหญ่ในการจัดระเบียบมันเป็นการเสียเวลาที่ค่อนข้างโง่มาก ...
Derek Litz

1
ฉันพบคำตอบนี้ฉันไม่มีปัญหากับองค์กรนี้
Isaiah Turner

คำตอบ:


84

ฉันเดาว่าคุณโพสต์คำถามนี้ในฟอรัม Amazon S3แต่เพื่อประโยชน์ของผู้อื่นฉันต้องการโพสต์คำตอบที่นี่:

หากมี "ชื่อไฟล์ผู้ใช้" เพียงรายการเดียวสำหรับอ็อบเจ็กต์ S3 แต่ละรายการคุณสามารถตั้งค่าส่วนหัว Content-Disposition ในไฟล์ s3 ของคุณเพื่อตั้งค่าชื่อไฟล์ดาวน์โหลด: Content-Disposition: attachment; ชื่อไฟล์ = foo.bar

เพื่อความเป็นธรรมฉันต้องการพูดถึงว่าไม่ใช่ฉันที่จะให้คำตอบที่ถูกต้องในฟอรัม Amazon และเครดิตทั้งหมดควรไปที่ Colin Rhodes ;-)


ใช่ขอบคุณที่เตือนฉัน ข้อมูลสำคัญอีกส่วนหนึ่งคือเมื่อเพิ่ม Content-Disposition จะต้องพิจารณากรณีและปัญหาและไม่จำเป็นต้องมีคำนำหน้า x-amz
Daveo

3
ลองดูคำตอบด้านล่างตั้งแต่เดือนมกราคม 2011 เป็นต้นไปนอกจากนี้ยังเป็นไปได้ตามคำขอ GET ดังนั้นจึงเป็นไปได้ที่จะมี "ชื่อไฟล์ผู้ใช้" มากเท่าที่คุณต้องการ
fabi

2
ฉันต้องการเพิ่มเครื่องหมายคำพูดให้กับชื่อไฟล์เพื่อให้สิ่งนี้ใช้งานได้ดังนั้นส่วนหัวของฉันคือ: Content-Disposition: attachment; filename = "foo.bar"
nathancahill

1
ใน c #: request.ResponseHeaderOverrides.ContentDisposition = "attachment; filename = foo.bar";
Amir M

2
คุณสามารถแทนที่ส่วนหัวการตอบสนองได้ทันที:https://...example.txt?response-content-disposition=attachment;filename=foo.bar
alaster

48

ในขณะที่คำตอบที่ยอมรับนั้นถูกต้อง แต่ฉันพบว่ามันเป็นนามธรรมและใช้ประโยชน์ได้ยาก

นี่คือโค้ด node.js ที่ช่วยแก้ปัญหาที่ระบุไว้ ฉันแนะนำให้ดำเนินการเป็น AWS Lambda เพื่อสร้าง 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...]

}

โปรดสังเกตResponseContentDispositionคุณลักษณะของparamsวัตถุที่ส่งเข้ามาในs3.getSignedUrlฟังก์ชัน

ข้อมูลเพิ่มเติมภายใต้ฟังก์ชั่น getObject doc ที่http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property


อาจจะไม่ชัดเจนฉันจะพยายามอธิบายให้ดีขึ้น แนวคิดคือฉันเก็บรายชื่อไฟล์ที่อัปโหลดไว้ในฐานข้อมูลและเมื่อมีคนต้องการดาวน์โหลดฉันจะรันแลมด้าด้วยoriginalFilenameพารามิเตอร์ as
Pawel

27

ในต้นเดือนมกราคม 2554 S3 ได้เพิ่มการแทนที่ส่วนหัวของคำขอ ฟังก์ชันนี้ช่วยให้คุณสามารถเปลี่ยนส่วนหัวการจัดการเนื้อหาสำหรับคำขอแต่ละรายการได้แบบไดนามิก

ดูเอกสาร S3 เกี่ยวกับการรับวัตถุสำหรับรายละเอียดเพิ่มเติม


4

ด้วย C # โดยใช้ 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);

3

สำหรับ Java AWS SDK ด้านล่าง Code Snippet ควรทำงาน:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);

0

ฉันมีปัญหาเดียวกันฉันแก้ไขได้โดยตั้งค่าส่วนหัว http "การจัดการเนื้อหา" ในขณะที่ส่งไฟล์ไปยัง S3 เวอร์ชัน SDK คือ AWS SDK สำหรับ PHP 3.x นี่คือเอกสารhttp://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

โค้ดส่วนหนึ่งของฉัน

    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

ดูเหมือนว่า response_content_disposition จะไม่มีเอกสารในเมธอด presigned_url นี่คือสิ่งที่ได้ผลสำหรับฉัน

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

0

ใช้ python และ 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"
        },
    )
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.