

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用檢查總和保護資料完整性
<a name="s3-checksums"></a>

Amazon Simple Storage Service (Amazon S3) 可讓您在上傳物件時指定檢查總和。當您指定檢查總和時，它會與 物件一起存放，並且可以在下載物件時進行驗證。

當您傳輸檔案時，檢查總和可提供多一層的資料完整性。使用檢查總和，您可以透過確認收到的檔案符合原始檔案來驗證資料一致性。如需使用 Amazon S3 檢查總和的詳細資訊，請參閱 [Amazon Simple Storage Service 使用者指南](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html)，包括[支援的演算法](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#using-additional-checksums)。

您可以靈活地選擇最符合您需求的演算法，並讓 SDK 計算檢查總和。或者，您可以使用其中一個支援的演算法來提供預先計算的檢查總和值。

**注意**  
從 2.30.0 版開始 AWS SDK for Java 2.x，開發套件會自動計算上傳的`CRC32`檢查總和，以提供預設完整性保護。如果您未提供預先計算的檢查總和值，或者您未指定 SDK 應該用來計算檢查總和的演算法，則 SDK 會計算此檢查總和。  
軟體開發套件還提供全域設定，用於外部設定的資料完整性保護，您可以在軟體[AWS SDKs和工具參考指南](https://docs.aws.amazon.com/sdkref/latest/guide/feature-dataintegrity.html)中閱讀這些保護。

我們討論兩個請求階段的檢查總和：上傳物件和下載物件。

## 上傳物件
<a name="use-service-S3-checksum-upload"></a>

當您使用 `putObject`方法上傳物件並提供檢查總和演算法時，開發套件會計算指定演算法的檢查總和。

下列程式碼片段顯示使用`SHA256`檢查總和上傳物件的請求。當 SDK 傳送請求時，它會計算`SHA256`檢查總和並上傳物件。Amazon S3 透過計算檢查總和並將其與 SDK 提供的檢查總和進行比較，來驗證內容的完整性。然後，Amazon S3 會將檢查總和與 物件一起存放。

```
public void putObjectWithChecksum() {
        s3Client.putObject(b -> b
                .bucket(bucketName)
                .key(key)
                .checksumAlgorithm(ChecksumAlgorithm.SHA256),
            RequestBody.fromString("This is a test"));
}
```

如果您未隨請求提供檢查總和演算法，檢查總和行為會根據您使用的 SDK 版本而有所不同，如下表所示。

**未提供檢查總和演算法時的檢查總和行為**


| Java 開發套件版本 | 檢查總和行為 | 
| --- | --- | 
| 早於 2.30.0 | 軟體開發套件不會自動計算以 CRC 為基礎的檢查總和，並在請求中提供它。 | 
| 2.30.0 或更新版本 | SDK 使用`CRC32`演算法來計算檢查總和，並在請求中提供檢查總和。Amazon S3 透過計算自己的`CRC32`檢查總和來驗證傳輸的完整性，並將其與 SDK 提供的檢查總和進行比較。如果檢查總和相符，檢查總和會與 物件一起儲存。 | 

### 使用預先計算的檢查總和值
<a name="use-service-S3-checksum-upload-pre"></a>

隨請求提供的預先計算檢查總和值會停用 SDK 的自動運算，並改用提供的值。

下列範例顯示具有預先計算 SHA256 檢查總和的請求。

```
    public void putObjectWithPrecalculatedChecksum(String filePath) {
        String checksum = calculateChecksum(filePath, "SHA-256");

        s3Client.putObject((b -> b
                .bucket(bucketName)
                .key(key)
                .checksumSHA256(checksum)),
            RequestBody.fromFile(Paths.get(filePath)));
    }
```

如果 Amazon S3 判斷指定演算法的檢查總和值不正確，則服務會傳回錯誤回應。

### 分段上傳
<a name="use-service-S3-checksum-upload-multi"></a>

您也可以使用具有分段上傳的檢查總和。

 適用於 Java 的 SDK 2.x 提供兩個選項，以使用具有分段上傳的檢查總和。第一個選項使用 `S3TransferManager`。

下列 Transfer Manager 範例會指定上傳的 SHA1 演算法。

```
    public void multipartUploadWithChecksumTm(String filePath) {
        S3TransferManager transferManager = S3TransferManager.create();
        UploadFileRequest uploadFileRequest = UploadFileRequest.builder()
            .putObjectRequest(b -> b
                .bucket(bucketName)
                .key(key)
                .checksumAlgorithm(ChecksumAlgorithm.SHA1))
            .source(Paths.get(filePath))
            .build();
        FileUpload fileUpload = transferManager.uploadFile(uploadFileRequest);
        fileUpload.completionFuture().join();
        transferManager.close();
    }
```

如果您在使用傳輸管理員進行上傳時未提供檢查總和演算法，軟體開發套件會根據`CRC32`演算法自動計算和檢查總和。軟體開發套件會針對所有版本的軟體開發套件執行此計算。

第二個選項使用 [`S3Client` API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html) （或 [`S3AsyncClient` API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html)) 來執行分段上傳。如果您使用此方法指定檢查總和，則必須指定啟動上傳時要使用的演算法。您還必須為每一個分段請求指定演算法，並在每一個分段上傳後提供為其計算的總和檢查。

```
    public void multipartUploadWithChecksumS3Client(String filePath) {
        ChecksumAlgorithm algorithm = ChecksumAlgorithm.CRC32;

        // Initiate the multipart upload.
        CreateMultipartUploadResponse createMultipartUploadResponse = s3Client.createMultipartUpload(b -> b
            .bucket(bucketName)
            .key(key)
            .checksumAlgorithm(algorithm)); // Checksum specified on initiation.
        String uploadId = createMultipartUploadResponse.uploadId();

        // Upload the parts of the file.
        int partNumber = 1;
        List<CompletedPart> completedParts = new ArrayList<>();
        ByteBuffer bb = ByteBuffer.allocate(1024 * 1024 * 5); // 5 MB byte buffer

        try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
            long fileSize = file.length();
            long position = 0;
            while (position < fileSize) {
                file.seek(position);
                long read = file.getChannel().read(bb);

                bb.flip(); // Swap position and limit before reading from the buffer.
                UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .uploadId(uploadId)
                    .checksumAlgorithm(algorithm) // Checksum specified on each part.
                    .partNumber(partNumber)
                    .build();

                UploadPartResponse partResponse = s3Client.uploadPart(
                    uploadPartRequest,
                    RequestBody.fromByteBuffer(bb));

                CompletedPart part = CompletedPart.builder()
                    .partNumber(partNumber)
                    .checksumCRC32(partResponse.checksumCRC32()) // Provide the calculated checksum.
                    .eTag(partResponse.eTag())
                    .build();
                completedParts.add(part);

                bb.clear();
                position += read;
                partNumber++;
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }

        // Complete the multipart upload.
        s3Client.completeMultipartUpload(b -> b
            .bucket(bucketName)
            .key(key)
            .uploadId(uploadId)
            .multipartUpload(CompletedMultipartUpload.builder().parts(completedParts).build()));
    }
```

[完整範例和測試的程式碼](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/PerformMultiPartUpload.java)位於 GitHub 程式碼範例儲存庫中。 [https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/test/java/com/example/s3/PerformMultiPartUploadTests.java](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/test/java/com/example/s3/PerformMultiPartUploadTests.java)

## 下載物件
<a name="use-service-S3-checksum-download"></a>

當您使用 [getObject](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#getObject(software.amazon.awssdk.services.s3.model.GetObjectRequest)) getObject方法下載物件時，開發套件會在當 的建置器 `checksumMode`方法`GetObjectRequest`設定為 時`ChecksumMode.ENABLED`。

以下程式碼片段中的請求會指示 SDK 透過計算檢查總和並比較值來驗證回應中的檢查總和。

```
    public GetObjectResponse getObjectWithChecksum() {
        return s3Client.getObject(b -> b
                        .bucket(bucketName)
                        .key(key)
                        .checksumMode(ChecksumMode.ENABLED))
                .response();
    }
```

**注意**  
如果物件未使用檢查總和上傳，則不會進行驗證。

## 其他檢查總和計算選項
<a name="S3-checsum-calculation-options"></a>

**注意**  
為了驗證傳輸資料的資料完整性並識別任何傳輸錯誤，我們建議使用者保留檢查總和計算選項的 SDK 預設設定。根據預設，軟體開發套件會針對許多 S3 操作新增此重要檢查，包括 `PutObject`和 `GetObject`。

不過，如果您使用 Amazon S3 需要最少的檢查總和驗證，您可以透過變更預設組態設定來停用許多檢查。

### 除非需要，否則停用自動檢查總和計算
<a name="S3-minimize-checksum-calc-global"></a>

您可以針對支援 SDK 的操作停用 SDK 的自動檢查總和計算，例如 `PutObject`和 `GetObject`。不過，某些 S3 操作需要檢查總和計算；您無法停用這些操作的檢查總和計算。

開發套件針對請求的承載和回應的承載，提供計算檢查總和的個別設定。

下列清單說明您可以用來將不同範圍的檢查總和計算降至最低的設定。
+ **所有應用程式範圍** - 透過變更環境變數中的設定或共用 AWS `config`和`credentials`檔案中的設定檔，所有應用程式都可以使用這些設定。除非在應用程式或服務用戶端範圍遭到覆寫，否則這些設定會影響所有 AWS SDK 應用程式中的所有服務用戶端。
  + 在設定檔中新增設定：

    ```
    [default]
    request_checksum_calculation = WHEN_REQUIRED
    response_checksum_validation = WHEN_REQUIRED
    ```
  + 新增環境變數：

    ```
    AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED
    AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED
    ```
+ **目前的應用程式範圍** - 您可以將 Java 系統屬性設定為 `aws.requestChecksumCalculation``WHEN_REQUIRED`，以限制檢查總和計算。回應的對應系統屬性為 `aws.responseChecksumValidation`。

  除非在建立服務用戶端期間遭到覆寫，否則這些設定會影響應用程式中的所有 SDK 服務用戶端。

  在應用程式開始時設定系統屬性：

  ```
  import software.amazon.awssdk.core.SdkSystemSetting;
  import software.amazon.awssdk.core.checksums.RequestChecksumCalculation;
  import software.amazon.awssdk.core.checksums.ResponseChecksumValidation;
  import software.amazon.awssdk.services.s3.S3Client;
  
  class DemoClass {
      public static void main(String[] args) {
  
          System.setProperty(SdkSystemSetting.AWS_REQUEST_CHECKSUM_CALCULATION.property(), // Resolves to "aws.requestChecksumCalculation".
                  "WHEN_REQUIRED");
          System.setProperty(SdkSystemSetting.AWS_RESPONSE_CHECKSUM_VALIDATION.property(), // Resolves to "aws.responseChecksumValidation".
                  "WHEN_REQUIRED");
  
          S3Client s3Client = S3Client.builder().build();
  
          // Use s3Client.
      }
  }
  ```
+ **單一 S3 服務用戶端範圍** - 您可以使用建置器方法，設定單一 S3 服務用戶端來計算檢查總和的最小數量：

  ```
  import software.amazon.awssdk.core.checksums.RequestChecksumCalculation;
  import software.amazon.awssdk.services.s3.S3Client;
  
  public class RequiredChecksums {
      public static void main(String[] args) {
          S3Client s3 = S3Client.builder()
                  .requestChecksumCalculation(RequestChecksumCalculation.WHEN_REQUIRED)
                  .responseChecksumValidation(ResponseChecksumValidation.WHEN_REQUIRED)
                  .build();
  
          // Use s3Client. 
      }
  // ...
  }
  ```

### 使用 `LegacyMd5Plugin`以簡化 MD5 相容性
<a name="S3-checksum-legacy-md5"></a>

除了發行 2.30.0 版的 CRC32 檢查總和行為之外，SDK 也停止計算必要操作的 MD5 檢查總和。

如果您需要 S3 操作的舊版 MD5 檢查總和行為，您可以使用 `LegacyMd5Plugin`，該 已隨 SDK 的 2.31.32 版發行。

當您需要與依賴舊版 MD5 檢查總和行為的應用程式保持相容性時，`LegacyMd5Plugin`特別有用，特別是在與第三方 S3-compatible儲存提供者搭配使用時，例如與 S3A 檔案系統連接器 (Apache Spark、Iceberg) 搭配使用時。

若要使用 `LegacyMd5Plugin`，請將其新增至 S3 用戶端建置器：

```
// For synchronous S3 client.
S3Client s3Client = S3Client.builder()
                           .addPlugin(LegacyMd5Plugin.create())
                           .build();

// For asynchronous S3 client.
S3AsyncClient asyncClient = S3AsyncClient.builder()
                                       .addPlugin(LegacyMd5Plugin.create())
                                       .build();
```

如果您想要將 MD5 檢查總和新增至需要檢查總和的操作，並想要略過為支援檢查總和但非必要的操作新增 SDK 預設檢查總和，您可以啟用`ClientBuilder`選項 `requestChecksumCalculation`和 `responseChecksumValidation`作為 `WHEN_REQUIRED`。這只會將 SDK 預設檢查總和新增至需要檢查總和的操作：

```
// Use the `LegacyMd5Plugin` with `requestChecksumCalculation` and `responseChecksumValidation` set to WHEN_REQUIRED.
S3AsyncClient asyncClient = S3AsyncClient.builder()
                                       .addPlugin(LegacyMd5Plugin.create())
                                       .requestChecksumCalculation(RequestChecksumCalculation.WHEN_REQUIRED)
                                       .responseChecksumValidation(ResponseChecksumValidation.WHEN_REQUIRED)
                                       .build();
```

此組態在使用可能無法完全支援較新檢查總和演算法，但仍需要特定操作的 MD5 檢查總和的第三方 S3-compatible儲存系統時特別有用。