Java上传对象到S3桶报无内容长度警告且代码中断该如何解决
问题原因
该警告及OOM崩溃的核心原因是:使用InputStream作为S3上传源时,你没有向ObjectMetadata实例声明流的总字节长度,AWS S3 SDK只能将整个流的全部内容缓冲到内存中自行计算长度,MB级及更大的文件很容易超出JVM堆内存上限,最终导致进程异常终止。
如果使用临时文件+分片上传的方案仍然失败,通常是因为分片上传逻辑中也没有正确传入对应分片/文件的长度参数,SDK仍然触发了内存缓冲逻辑。
修复方案
方案1:补充ContentLength配置(适配现有单文件上传逻辑)
在当前代码的metadata配置步骤中,追加上传内容的长度配置即可,修改后代码如下:
InputStream inputStream = part.getInputStream(); AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withRegion("eu-central-1") .build(); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType(part.getContentType()); // 新增行:传入上传内容的总字节长度,若part为ServletPart实例可直接调用getSize()获取 metadata.setContentLength(part.getSize()); logger.log("setting metadata"); PutObjectRequest request = new PutObjectRequest(bucket, fileName, inputStream, metadata); s3Client.putObject(request); logger.log("putting in S3 bucket");
如果你的part实例没有直接获取大小的方法,也可以先将流转换为字节数组后读取长度,单文件≤100MB时该方案更稳妥:
byte[] fileBytes = org.apache.commons.io.IOUtils.toByteArray(inputStream); metadata.setContentLength(fileBytes.length); // 原流已被读取完毕,需重新构造输入流传入请求 PutObjectRequest request = new PutObjectRequest(bucket, fileName, new ByteArrayInputStream(fileBytes), metadata);
方案2:使用File作为上传入参(无需手动设置长度)
如果已经将上传内容保存为本地临时文件,可直接将File实例传入PutObjectRequest,SDK会自动读取文件长度,无需手动配置ContentLength:
// tempFile为你保存的本地临时文件对象 PutObjectRequest request = new PutObjectRequest(bucket, fileName, tempFile); s3Client.putObject(request);
- 注意:单文件超过100MB时优先使用分片上传,降低单次上传失败的重传成本,分片大小建议设置在5MB~100MB区间,每个分片上传时也需要对应传入分片的字节长度。
内容的提问来源于stack exchange,提问作者EmanAKhan
相关产品推荐
相关产品推荐

