如何用校验和验证AWS S3文件上传成功及本地与S3文件一致性?
利用校验和验证S3文件上传及一致性校验
一、上传阶段启用校验和验证
AWS S3支持MD5、SHA-256等多种校验和算法,上传时可主动传递本地计算的校验和,让S3自动对比自身计算的结果,若不一致则返回错误,以此验证上传是否成功。
1. 先实现本地文件校验和计算工具
import java.io.FileInputStream; import java.security.MessageDigest; import java.util.Base64; public class ChecksumUtils { // 计算文件MD5校验和(Base64编码,匹配S3的Content-MD5格式) public static String calculateMD5(String filePath) throws Exception { MessageDigest md = MessageDigest.getInstance("MD5"); try (FileInputStream fis = new FileInputStream(filePath)) { byte[] buffer = new byte[8192]; int readLen; while ((readLen = fis.read(buffer)) != -1) { md.update(buffer, 0, readLen); } } return Base64.getEncoder().encodeToString(md.digest()); } // 计算文件SHA-256校验和(更高安全性) public static String calculateSHA256(String filePath) throws Exception { MessageDigest md = MessageDigest.getInstance("SHA-256"); try (FileInputStream fis = new FileInputStream(filePath)) { byte[] buffer = new byte[8192]; int readLen; while ((readLen = fis.read(buffer)) != -1) { md.update(buffer, 0, readLen); } } return Base64.getEncoder().encodeToString(md.digest()); } }
2. 修改上传代码,添加校验和验证逻辑
public class S3Uploader { @Autowired private S3TransferManager transferManager; public String uploadFile(String bucketName, String key, String filePath) throws Exception { // 计算本地文件MD5 String localMD5 = ChecksumUtils.calculateMD5(filePath); UploadFileRequest uploadFileRequest = UploadFileRequest.builder() .putObjectRequest(b -> b .bucket(bucketName) .key(key) // 传递本地MD5,S3会自动对比校验 .contentMD5(localMD5)) .addTransferListener(LoggingTransferListener.create()) .source(Paths.get(filePath)) .build(); FileUpload fileUpload = transferManager.uploadFile(uploadFileRequest); // 若校验失败,completionFuture().join()会抛出SdkException CompletedFileUpload uploadResult = fileUpload.completionFuture().join(); return uploadResult.response().eTag(); } }
说明:如果S3计算的校验和与你传递的不一致,会直接抛出异常,此时可判定上传失败。
二、上传后校验本地与S3文件的一致性
上传完成后,可主动获取S3文件的校验和,与本地文件的校验和对比,确认文件一致。
方式1:通过S3文件元数据获取校验和对比
import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.HeadObjectRequest; import software.amazon.awssdk.services.s3.model.HeadObjectResponse; @Autowired private S3Client s3Client; public boolean verifyFileConsistency(String bucketName, String key, String localFilePath) throws Exception { // 计算本地文件MD5 String localMD5 = ChecksumUtils.calculateMD5(localFilePath); // 获取S3文件的MD5校验和 HeadObjectRequest headReq = HeadObjectRequest.builder() .bucket(bucketName) .key(key) .build(); HeadObjectResponse headResp = s3Client.headObject(headReq); String s3MD5 = headResp.contentMD5(); // 对比校验和 return localMD5.equals(s3MD5); }
如果使用SHA-256,上传时需在PutObjectRequest中调用.checksumSHA256(localSHA256),获取时从headResp.checksumSHA256()取值对比即可。
方式2:利用ETag对比(仅限单文件非分块上传场景)
普通单文件上传时,S3返回的ETag等于文件MD5(需去掉前后引号),但分块上传时ETag是分块MD5的组合值,无法直接对比。若确认是单文件上传,可使用此方式:
public boolean verifyWithETag(String bucketName, String key, String localFilePath) throws Exception { String localMD5 = ChecksumUtils.calculateMD5(localFilePath); // 去掉ETag的前后引号 String s3ETag = s3Client.headObject(HeadObjectRequest.builder().bucket(bucketName).key(key).build()) .eTag().replace("\"", ""); return localMD5.equals(s3ETag); }
关键注意事项
- 分块上传场景:分块上传的ETag不等于单个文件MD5,必须使用S3返回的
checksumMD5或checksumSHA256进行对比。 - 算法选择:追求更高安全性优先选SHA-256,MD5适合普通校验场景。
- 异常处理:计算校验和、请求S3时可能抛出IO或SDK异常,需自行捕获处理。
内容的提问来源于stack exchange,提问作者Pale Blue Dot
相关产品推荐
相关产品推荐

