Amazon S3 Name des Dateidownloads ändern

90

Ich habe Dateien in S3 mit einer GUID als Schlüsselnamen gespeichert.

Ich verwende eine vorsignierte URL zum Herunterladen gemäß der S3-REST-API

Ich speichere den ursprünglichen Dateinamen in meiner eigenen Datenbank. Wenn ein Benutzer auf klickt, um eine Datei von meiner Webanwendung herunterzuladen, möchte ich seinen ursprünglichen Dateinamen zurückgeben. Derzeit erhält er jedoch nur eine GUID . Wie kann ich das erreichen?

Meine Web-App befindet sich in Salesforce, daher habe ich nicht viel Kontrolle über die Antwort. Leitet alle Dateien herunter, die auf den Webserver heruntergeladen wurden, und benennt sie dann aufgrund von Governor-Einschränkungen um.

Gibt es eine HTML-Umleitung, Meta-Aktualisierung, Javascript, die ich verwenden kann? Gibt es eine Möglichkeit, den Namen der Download-Datei für S3 zu ändern (ich kann mir nur vorstellen, das Objekt unter einen neuen Namen zu kopieren, herunterzuladen und dann zu löschen).

Ich möchte vermeiden, einen Bucket pro Benutzer zu erstellen, da wir viele Benutzer haben und dennoch nicht garantieren können, dass jede Datei in jedem Bucket einen eindeutigen Namen hat

Irgendwelche anderen Lösungen?

Daveo
quelle
5
Eine weitere legitime SO-Frage, die als Off-Topic geschlossen wurde! Die Frage und die Antworten haben auch mehr Stimmen als die überwiegende Mehrheit der üblichen Fragen / Antworten ...
DeepSpace101
Ja, es ist offensichtlich wichtiger, dass wir versuchen, die Dinge etwas willkürlich zu organisieren, angesichts der Tatsache, dass es in Zukunft oder sogar jetzt nicht garantiert Sinn macht. Was ist passiert, wenn die Leute einfach Spaß daran hatten, Fragen zur Softwareindustrie zu stellen und zu beantworten? Wer findet aufgrund dieser Organisation tatsächlich die Antwort? Wer findet eine Organisationsstruktur in Software branchenweit einheitlich und klar definiert? Ohne diese klare Definition, die viel Zeit für die Organisation benötigt, ist es eine ziemlich dumme Zeitverschwendung ...
Derek Litz
1
Ich finde diese Antwort, ich habe kein Problem mit dieser Organisation.
Jesaja Turner

Antworten:

80

Ich denke, Ihr Kreuz hat diese Fragen im Amazon S3-Forum gepostet , aber für andere möchte ich die Antwort hier posten:

Wenn es für jedes S3-Objekt immer nur einen "Benutzerdateinamen" gibt, können Sie den Content-Disposition-Header in Ihrer S3-Datei festlegen, um den Download-Dateinamen festzulegen: Content-Disposition: Anhang; Dateiname = foo.bar

Aus Gründen der Fairness möchte ich erwähnen, dass ich nicht die richtige Antwort im Amazon-Forum gegeben habe und alle Credits an Colin Rhodes gehen sollten ;-)

Cloudberryman
quelle
Ja, danke, dass du mich daran erinnert hast. Die andere wichtige Information ist, dass beim Hinzufügen von Content-Disposition zwischen Groß- und Kleinschreibung unterschieden wird und NICHT im Präfix x-amz benötigt wird.
Daveo
3
Schauen Sie sich die Antwort unten an. Seit Januar 2011 ist dies auch pro GET-Anfrage möglich. Es ist also möglich, so viele "Benutzerdateinamen" zu haben, wie Sie möchten.
Fabi
2
Ich musste dem Dateinamen Anführungszeichen hinzufügen, damit dies funktioniert, daher lautete mein Header: Inhaltsdisposition: Anhang; Dateiname = "foo.bar"
nathancahill
1
In c #: request.ResponseHeaderOverrides.ContentDisposition = "Anhang; Dateiname = foo.bar";
Amir M
1
Sie könnten Antwort-Header im https://...example.txt?response-content-disposition=attachment;filename=foo.bar
laufenden Betrieb
40

Obwohl die akzeptierte Antwort richtig ist, finde ich sie sehr abstrakt und schwer zu verwenden.

Hier ist ein Teil des Codes von node.js, der das angegebene Problem löst. Ich empfehle, es als AWS Lambda auszuführen, um eine vorsignierte URL zu generieren.

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

}

Bitte beachten Sie das ResponseContentDispositionAttribut des paramsin die s3.getSignedUrlFunktion übergebenen Objekts .

Weitere Informationen finden Sie unter getObject function doc unter http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property

Pawel
quelle
Vielleicht ist es nicht offensichtlich, ich werde versuchen, es besser zu erklären. Die Idee ist, dass ich die Liste der Namen der hochgeladenen Dateien in der Datenbank behalte und dann, wenn jemand sie herunterladen möchte, Lambda mit einem originalFilenameas-Parameter ausführe .
Pawel
26

Anfang Januar 2011 hat S3 Anforderungsheader-Überschreibungen hinzugefügt. Mit dieser Funktion können Sie den Content-Disposition-Header für einzelne Anforderungen "dynamisch" ändern.

Weitere Informationen finden Sie in der S3- Dokumentation zum Abrufen von Objekten .

Uriah Carpenter
quelle
3

Für Java AWS SDK unten sollte Code Snippet die Aufgabe erledigen:

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

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

generatePresignedUrlRequest.setResponseHeaders(responseHeaders);
Abhishek Basak
quelle
3

Mit C # unter Verwendung von 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);
hkutluay
quelle
0

Ich habe das gleiche Problem, ich habe es gelöst, indem ich den http-Header "content-disposition" gesetzt habe, während ich die Datei an S3 gesendet habe. Die SDK-Version ist AWS SDK für PHP 3.x. Hier ist das Dokument http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

ein Stück meines Codes

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

Es sieht so aus: response_content_disposition ist in der presigned_url-Methode nicht dokumentiert. Das hat bei mir funktioniert

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