Amazon S3 Zmień nazwę pobierania pliku

103

Mam pliki zapisane na S3 z identyfikatorem GUID jako nazwą klucza.

Używam wstępnie podpisanego adresu URL do pobrania zgodnie z interfejsem API REST S3

Przechowuję oryginalną nazwę pliku w mojej własnej bazie danych. Kiedy użytkownik kliknie, aby pobrać plik z mojej aplikacji internetowej , chcę zwrócić jego oryginalną nazwę pliku, ale obecnie wszystko, co otrzymuje, to identyfikator GUID . Jak mogę to osiągnąć?

Moja aplikacja internetowa jest w Salesforce, więc nie mam dużej kontroli nad odpowiedzią. Przekierowuje wszystkie pobieranie pliku na serwer sieciowy, a następnie zmienia jego nazwę z powodu ograniczeń zarządcy.

Czy jest jakieś przekierowanie HTML, odświeżanie meta, JavaScript, którego mogę użyć? Czy istnieje sposób na zmianę nazwy pliku pobierania dla S3 (jedyne, o czym przychodzi mi do głowy, to skopiowanie obiektu do nowej nazwy, pobranie go, a następnie usunięcie).

Chcę uniknąć tworzenia zasobnika na użytkownika, ponieważ będziemy mieć wielu użytkowników i nadal nie ma gwarancji, że każdy plik w każdym zasobniku będzie miał niepowtarzalną nazwę

Jakieś inne rozwiązania?

Daveo
źródło
7
Kolejne uzasadnione pytanie, które zostało zamknięte jako nie na temat! Pytanie i odpowiedzi również mają więcej głosów niż zdecydowana większość zwykłych pytań / odpowiedzi ...
DeepSpace101
Tak, oczywiście ważniejsze jest, abyśmy spróbowali uporządkować sprawy nieco arbitralnie, w obliczu faktu, że nie ma gwarancji, że będzie to miało sens w przyszłości lub nawet teraz. Co się stało, gdy ludzie po prostu dobrze się bawili zadając pytania związane z branżą oprogramowania i odpowiadając na nie? Kto właściwie znajduje odpowiedź z powodu tej organizacji? Kto uważa, że ​​jakakolwiek struktura organizacyjna oprogramowania jest spójna i jasno zdefiniowana w całej branży? Bez tej jasnej definicji, która potrwa znaczną ilość czasu, organizacja jest dość głupią stratą czasu ...
Derek Litz
1
Znajduję tę odpowiedź, nie mam problemu z tą organizacją.
Isaiah Turner,

Odpowiedzi:

84

Domyślam się, że Twój krzyż opublikował to pytanie na forum Amazon S3 , ale dla dobra innych chciałbym zamieścić odpowiedź tutaj:

Jeśli istnieje tylko jedna „nazwa pliku użytkownika” dla każdego obiektu S3, możesz ustawić nagłówek Content-Disposition w pliku s3, aby ustawić nazwę pobierania: Content-Disposition: załącznik; filename = foo.bar

Ze względu na uczciwość chciałbym wspomnieć, że to nie ja udzieliłem właściwej odpowiedzi na forum Amazona i wszystkie kredyty powinny trafić do Colina Rhodesa ;-)

cloudberryman
źródło
tak, dziękuję za przypomnienie. Inną ważną informacją jest to, że podczas dodawania Content-Disposition rozróżnia się wielkość liter i NIE wymaga przedrostka x-amz.
Daveo,
3
Spójrz na odpowiedź poniżej, od stycznia 2011 jest to również możliwe na podstawie żądania GET. Można więc mieć dowolną liczbę „nazw plików użytkowników”.
fabi
2
Musiałem dodać cudzysłowy do nazwy pliku, aby to zadziałało, więc mój nagłówek brzmiał: Content-Disposition: załącznik; filename = "
foo.bar
1
W c #: request.ResponseHeaderOverrides.ContentDisposition = "załącznik; filename = foo.bar";
Amir M
2
Możesz zmienić nagłówki odpowiedzi w locie:https://...example.txt?response-content-disposition=attachment;filename=foo.bar
alaster
48

Chociaż przyjęta odpowiedź jest prawidłowa, uważam ją za bardzo abstrakcyjną i trudną do wykorzystania.

Oto fragment kodu node.js, który rozwiązuje przedstawiony problem. Radzę wykonać to jako AWS Lambda w celu wygenerowania wstępnie podpisanego adresu 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...]

}

Proszę zwrócić uwagę na ResponseContentDispositionatrybut paramsobiektu przekazany do s3.getSignedUrlfunkcji.

Więcej informacji w dokumencie funkcji getObject pod adresem http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property

Paweł
źródło
Może nie jest to oczywiste, postaram się wyjaśnić lepiej. Chodzi o to, że listę nazw wgranych plików przechowuję w bazie danych, a gdy ktoś chce je pobrać, wykonuję lambdę z originalFilenameparametrem as.
Paweł
27

Na początku stycznia 2011 r. S3 dodał nadpisania nagłówka żądania. Ta funkcja umożliwia „dynamiczną” zmianę nagłówka Content-Disposition dla poszczególnych żądań.

Zobacz dokumentację S3 dotyczącą pobierania obiektów, aby uzyskać więcej informacji.

Uriah Carpenter
źródło
4

W C # używającym 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
źródło
3

W przypadku zestawu Java AWS SDK poniżej fragment kodu powinien wykonać zadanie:

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
źródło
0

Mam ten sam problem, rozwiązałem go ustawiając nagłówek http "content-disposition" podczas przesyłania pliku do S3, wersja SDK to AWS SDK dla PHP 3.x. tutaj jest dokument http://docs.amazonaws.cn/en_us/aws-sdk-php/latest/api-s3-2006-03-01.html#putobject

kawałek mojego kodu

    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
źródło
0

Wygląda na to, że: response_content_disposition nie jest udokumentowana w metodzie presigned_url. To właśnie zadziałało dla mnie

    signer = Aws::S3::Presigner.new
    signer.presigned_url(:get_object, bucket: @bucket, key: filename, 
    response_content_disposition: "attachment; filename =#{new_name}")
Chris Mcdonald
źródło
0

Korzystanie z Pythona i 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"
        },
    )
Udi
źródło