View a markdown version of this page

Bekerja dengan Amazon S3 URL yang telah ditandatangani sebelumnya - AWS SDK for Java 2.x

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Bekerja dengan Amazon S3 URL yang telah ditandatangani sebelumnya

Pre-signed URL menyediakan akses sementara ke objek S3 pribadi tanpa mengharuskan pengguna memiliki AWS kredensyal atau izin.

Misalnya, asumsikan Alice memiliki akses ke objek S3, dan dia ingin sementara berbagi akses ke objek itu dengan Bob. Alice dapat membuat permintaan GET yang telah ditandatangani sebelumnya untuk dibagikan dengan Bob sehingga ia dapat mengunduh objek tanpa memerlukan akses ke kredensyal Alice. Anda dapat membuat URL pra-ditandatangani untuk HTTP GET dan untuk permintaan HTTP PUT.

Buat URL yang telah ditandatangani sebelumnya untuk suatu objek, lalu unduh (GET request)

Contoh berikut terdiri dari dua bagian.

  • Bagian 1: Alice menghasilkan URL pra-ditandatangani untuk objek.

  • Bagian 2: Bob mengunduh objek dengan menggunakan URL yang telah ditandatangani sebelumnya.

Bagian 1: Menghasilkan URL

Alice sudah memiliki objek di ember S3. Dia menggunakan kode berikut untuk menghasilkan string URL yang dapat digunakan Bob dalam permintaan GET berikutnya.

import com.example.s3.util.PresignUrlUtils; import org.slf4j.Logger; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; import software.amazon.awssdk.utils.IoUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Paths; import java.time.Duration; import java.util.UUID;
/* Create a pre-signed URL to download an object in a subsequent GET request. */ public String createPresignedGetUrl(String bucketName, String keyName) { try (S3Presigner presigner = S3Presigner.create()) { GetObjectRequest objectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) // The URL will expire in 10 minutes. .getObjectRequest(objectRequest) .build(); PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest); logger.info("Presigned URL: [{}]", presignedRequest.url().toString()); logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method()); return presignedRequest.url().toExternalForm(); } }

Bagian 2: Unduh objek

Bob menggunakan salah satu opsi kode berikut untuk mengunduh objek. Atau, dia bisa menggunakan browser untuk melakukan permintaan GET.

/* Use the JDK HttpURLConnection (since v1.1) class to do the download. */ public byte[] useHttpUrlConnectionToGet(String presignedUrlString) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array. try { URL presignedUrl = new URL(presignedUrlString); HttpURLConnection connection = (HttpURLConnection) presignedUrl.openConnection(); connection.setRequestMethod("GET"); // Download the result of executing the request. try (InputStream content = connection.getInputStream()) { IoUtils.copy(content, byteArrayOutputStream); } logger.info("HTTP response code is " + connection.getResponseCode()); } catch (S3Exception | IOException e) { logger.error(e.getMessage(), e); } return byteArrayOutputStream.toByteArray(); }
/* Use the JDK HttpClient (since v11) class to do the download. */ public byte[] useHttpClientToGet(String presignedUrlString) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array. HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); HttpClient httpClient = HttpClient.newHttpClient(); try { URL presignedUrl = new URL(presignedUrlString); HttpResponse<InputStream> response = httpClient.send(requestBuilder .uri(presignedUrl.toURI()) .GET() .build(), HttpResponse.BodyHandlers.ofInputStream()); IoUtils.copy(response.body(), byteArrayOutputStream); logger.info("HTTP response code is " + response.statusCode()); } catch (URISyntaxException | InterruptedException | IOException e) { logger.error(e.getMessage(), e); } return byteArrayOutputStream.toByteArray(); }
/* Use the AWS SDK for Java SdkHttpClient class to do the download. */ public byte[] useSdkHttpClientToGet(String presignedUrlString) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array. try { URL presignedUrl = new URL(presignedUrlString); SdkHttpRequest request = SdkHttpRequest.builder() .method(SdkHttpMethod.GET) .uri(presignedUrl.toURI()) .build(); HttpExecuteRequest executeRequest = HttpExecuteRequest.builder() .request(request) .build(); try (SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) { HttpExecuteResponse response = sdkHttpClient.prepareRequest(executeRequest).call(); response.responseBody().ifPresentOrElse( abortableInputStream -> { try { IoUtils.copy(abortableInputStream, byteArrayOutputStream); } catch (IOException e) { throw new RuntimeException(e); } }, () -> logger.error("No response body.")); logger.info("HTTP Response code is {}", response.httpResponse().statusCode()); } } catch (URISyntaxException | IOException e) { logger.error(e.getMessage(), e); } return byteArrayOutputStream.toByteArray(); }

AWS SDK for Java 2.x Ini menyediakan ekstensi URL yang telah ditandatangani sebelumnya pada objek unduhan S3AsyncClient tersebut menggunakan URL yang telah ditandatangani sebelumnya melalui pipeline async SDK. Akses ekstensi denganS3AsyncClient.presignedUrlExtension(). Fitur ini tersedia dalam versi SDK 2.48.0 dan yang lebih baru.

Batasan klien CRT

Klien AWS CRT-based S3 (S3AsyncClient.crtBuilder()) saat ini tidak mendukung ekstensi URL yang telah ditandatangani sebelumnya. Gunakan S3AsyncClient.builder() sebagai gantinya.

Persyaratan mode checksum

Untuk memvalidasi integritas data, tetapkan checksumMode(ChecksumMode.ENABLED) pada GetObjectRequest saat Anda membuat URL yang telah ditandatangani sebelumnya. Tentukan mode checksum pada waktu presign. Anda tidak dapat menambahkannya nanti saat menjalankan unduhan. Saat Anda menggunakan ekstensi URL yang S3AsyncClient telah ditandatangani sebelumnya, SDK secara otomatis mengirimkan header yang diperlukanx-amz-checksum-mode.

import java.nio.file.Paths; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.presignedurl.model.PresignedUrlDownloadRequest;
Unduh ke file atau byte
Download to file
S3AsyncClient s3AsyncClient = S3AsyncClient.builder() .region(Region.US_EAST_1) .build(); GetObjectResponse response = s3AsyncClient.presignedUrlExtension() .getObject( PresignedUrlDownloadRequest.builder() .presignedUrl(presignedGetObjectRequest.url()) .build(), Paths.get("/tmp/downloaded-file.bin")) .join(); // Or use the consumer builder pattern GetObjectResponse response = s3AsyncClient.presignedUrlExtension() .getObject( r -> r.presignedUrl(presignedGetObjectRequest.url()), Paths.get("/tmp/downloaded-file.bin")) .join();
Download to bytes
S3AsyncClient s3AsyncClient = S3AsyncClient.builder() .region(Region.US_EAST_1) .build(); ResponseBytes<GetObjectResponse> bytes = s3AsyncClient.presignedUrlExtension() .getObject( PresignedUrlDownloadRequest.builder() .presignedUrl(presignedGetObjectRequest.url()) .build(), AsyncResponseTransformer.toBytes()) .join(); // Or use the consumer builder pattern ResponseBytes<GetObjectResponse> bytes = s3AsyncClient.presignedUrlExtension() .getObject( r -> r.presignedUrl(presignedGetObjectRequest.url()), AsyncResponseTransformer.toBytes()) .join();
Unduhan multipart untuk file besar

Untuk mengunduh objek besar secara paralel, atur multipartEnabled(true) pada klien:

Download to file
S3AsyncClient multipartClient = S3AsyncClient.builder() .region(Region.US_EAST_1) .multipartEnabled(true) .multipartConfiguration(c -> c.minimumPartSizeInBytes(8 * 1024 * 1024L)) .build(); GetObjectResponse response = multipartClient.presignedUrlExtension() .getObject( PresignedUrlDownloadRequest.builder() .presignedUrl(presignedGetObjectRequest.url()) .build(), Paths.get("/tmp/large-file.bin")) .join();
Download to bytes
S3AsyncClient multipartClient = S3AsyncClient.builder() .region(Region.US_EAST_1) .multipartEnabled(true) .multipartConfiguration(c -> c.minimumPartSizeInBytes(8 * 1024 * 1024L)) .build(); ResponseBytes<GetObjectResponse> bytes = multipartClient.presignedUrlExtension() .getObject( PresignedUrlDownloadRequest.builder() .presignedUrl(presignedGetObjectRequest.url()) .build(), AsyncResponseTransformer.toBytes()) .join();
Gunakan Manajer Transfer Amazon S3

Dengan Amazon S3 Transfer Manager, Anda dapat mengunduh objek menggunakan URL yang telah ditandatangani sebelumnya dengan pelacakan kemajuan. TransferListener

Tambahkan s3-transfer-manager artefak ke proyek Anda:

<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.48.01</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3-transfer-manager</artifactId> </dependency> </dependencies>

1 Temukan versi BOM terbaru di Maven Central Repository.

import java.nio.file.Paths; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.presignedurl.model.PresignedUrlDownloadRequest; import software.amazon.awssdk.transfer.s3.S3TransferManager; import software.amazon.awssdk.transfer.s3.model.CompletedFileDownload; import software.amazon.awssdk.transfer.s3.model.Download; import software.amazon.awssdk.transfer.s3.model.PresignedDownloadFileRequest; import software.amazon.awssdk.transfer.s3.model.PresignedDownloadRequest; import software.amazon.awssdk.transfer.s3.model.PresignedFileDownload; import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener;
Download to file
S3TransferManager transferManager = S3TransferManager.create(); PresignedFileDownload fileDownload = transferManager.downloadFileWithPresignedUrl( PresignedDownloadFileRequest.builder() .presignedUrlDownloadRequest(PresignedUrlDownloadRequest.builder() .presignedUrl(presignedGetObjectRequest.url()) .build()) .destination(Paths.get("/tmp/transfer-download.bin")) .addTransferListener(LoggingTransferListener.create()) .build()); CompletedFileDownload completed = fileDownload.completionFuture().join();
Download to bytes
S3TransferManager transferManager = S3TransferManager.create(); Download<ResponseBytes<GetObjectResponse>> bytesDownload = transferManager.downloadWithPresignedUrl( PresignedDownloadRequest.<ResponseBytes<GetObjectResponse>>builder() .presignedUrlDownloadRequest(PresignedUrlDownloadRequest.builder() .presignedUrl(presignedGetObjectRequest.url()) .build()) .responseTransformer(AsyncResponseTransformer.toBytes()) .addTransferListener(LoggingTransferListener.create()) .build()); ResponseBytes<GetObjectResponse> result = bytesDownload.completionFuture().join().result();
Jeda dan lanjutkan tidak didukung

Tidak seperti biasaFileDownload, PresignedFileDownload tidak mendukung jeda dan melanjutkan karena URL yang telah ditandatangani sebelumnya dapat kedaluwarsa selama transfer yang dijeda.

Untuk informasi selengkapnya tentang Manajer Transfer Amazon S3, termasuk opsi konfigurasi dan contoh tambahan, lihat. Transfer file dan direktori dengan Amazon S3 Transfer Manager

Lihat contoh lengkapnya dan uji GitHub.

Buat URL yang telah ditandatangani sebelumnya untuk unggahan, lalu unggah file (permintaan PUT)

Contoh berikut terdiri dari dua bagian.

  • Bagian 1: Alice menghasilkan URL yang telah ditandatangani sebelumnya untuk mengunggah objek.

  • Bagian 2: Bob mengunggah file dengan menggunakan URL yang telah ditandatangani sebelumnya.

Bagian 1: Menghasilkan URL

Alice sudah memiliki ember S3. Dia menggunakan kode berikut untuk menghasilkan string URL yang dapat digunakan Bob dalam permintaan PUT berikutnya.

import com.example.s3.util.PresignUrlUtils; import org.slf4j.Logger; import software.amazon.awssdk.core.internal.sync.FileContentStreamProvider; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest; import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.util.Map; import java.util.UUID;
/* Create a presigned URL to use in a subsequent PUT request */ public String createPresignedUrl(String bucketName, String keyName, Map<String, String> metadata) { try (S3Presigner presigner = S3Presigner.create()) { PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(keyName) .metadata(metadata) .build(); PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) // The URL expires in 10 minutes. .putObjectRequest(objectRequest) .build(); PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest); String myURL = presignedRequest.url().toString(); logger.info("Presigned URL to upload a file to: [{}]", myURL); logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method()); return presignedRequest.url().toExternalForm(); } }

Bagian 2: Unggah objek file

Bob menggunakan salah satu dari tiga opsi kode berikut untuk mengunggah file.

/* Use the JDK HttpURLConnection (since v1.1) class to do the upload. */ public void useHttpUrlConnectionToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) { logger.info("Begin [{}] upload", fileToPut.toString()); try { URL presignedUrl = new URL(presignedUrlString); HttpURLConnection connection = (HttpURLConnection) presignedUrl.openConnection(); connection.setDoOutput(true); metadata.forEach((k, v) -> connection.setRequestProperty("x-amz-meta-" + k, v)); connection.setRequestMethod("PUT"); OutputStream out = connection.getOutputStream(); try (RandomAccessFile file = new RandomAccessFile(fileToPut, "r"); FileChannel inChannel = file.getChannel()) { ByteBuffer buffer = ByteBuffer.allocate(8192); //Buffer size is 8k while (inChannel.read(buffer) > 0) { buffer.flip(); for (int i = 0; i < buffer.limit(); i++) { out.write(buffer.get()); } buffer.clear(); } } catch (IOException e) { logger.error(e.getMessage(), e); } out.close(); connection.getResponseCode(); logger.info("HTTP response code is " + connection.getResponseCode()); } catch (S3Exception | IOException e) { logger.error(e.getMessage(), e); } }
/* Use the JDK HttpClient (since v11) class to do the upload. */ public void useHttpClientToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) { logger.info("Begin [{}] upload", fileToPut.toString()); HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); metadata.forEach((k, v) -> requestBuilder.header("x-amz-meta-" + k, v)); HttpClient httpClient = HttpClient.newHttpClient(); try { final HttpResponse<Void> response = httpClient.send(requestBuilder .uri(new URL(presignedUrlString).toURI()) .PUT(HttpRequest.BodyPublishers.ofFile(Path.of(fileToPut.toURI()))) .build(), HttpResponse.BodyHandlers.discarding()); logger.info("HTTP response code is " + response.statusCode()); } catch (URISyntaxException | InterruptedException | IOException e) { logger.error(e.getMessage(), e); } }
/* Use the AWS SDK for Java V2 SdkHttpClient class to do the upload. */ public void useSdkHttpClientToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) { logger.info("Begin [{}] upload", fileToPut.toString()); try { URL presignedUrl = new URL(presignedUrlString); SdkHttpRequest.Builder requestBuilder = SdkHttpRequest.builder() .method(SdkHttpMethod.PUT) .uri(presignedUrl.toURI()); // Add headers metadata.forEach((k, v) -> requestBuilder.putHeader("x-amz-meta-" + k, v)); // Finish building the request. SdkHttpRequest request = requestBuilder.build(); HttpExecuteRequest executeRequest = HttpExecuteRequest.builder() .request(request) .contentStreamProvider(new FileContentStreamProvider(fileToPut.toPath())) .build(); try (SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) { HttpExecuteResponse response = sdkHttpClient.prepareRequest(executeRequest).call(); logger.info("Response code: {}", response.httpResponse().statusCode()); } } catch (URISyntaxException | IOException e) { logger.error(e.getMessage(), e); } }

Lihat contoh lengkapnya dan uji GitHub.