有时使用Java SDK,Amazon S3文件上传失败,

时间:2018-07-23 21:27:16

标签: amazon-web-services spring-boot amazon-s3

在将文件上传到AmazonS3时,我遇到一种非常奇怪的行为。

在大多数情况下(占上传总数的97%),此代码可以完美运行。 putObject方法的其他3%执行正确,但是之后我无法恢复该文件。它不在存储桶中。

代码如下:

@Override
public String uploadAppFileToS3(File file, Long appId, String fileName) throws IOException {

FileInputStream stream;

BasicAWSCredentials awsCredentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey);
AmazonS3 s3 = AmazonS3ClientBuilder.standard()
    .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
    .withRegion(Regions.EU_WEST_3) //eu-west-3 EU(Paris)
    .build();

String contentType = Files.probeContentType(file.toPath());
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(contentType);
stream = new FileInputStream(file);
metadata.setContentLength(file.length());

String fileS3Key = appId + "/" + fileName;
s3.putObject(s3BucketName, fileS3Key, stream, metadata);

//Clear resources
stream.close();

return fileS3Key;
}

此代码从Spring Boot端点调用:

/**
 * This method will handle the file upload to Amazon S3
 */
@PostMapping("/application/upload/{id}")
@ResponseBody
public AppFileDTO uploadFile(@RequestParam("file") MultipartFile file, @PathVariable Long id,
    Model model) throws IOException {

  //Get the app from the database
  Application app = applicationService.findById(id);
  model.addAttribute("app", app);

  //Store the file temporarily
  File temporalFile = new File(temporalStoragePath + file.getName());
  file.transferTo(temporalFile);

  String fileS3Key = appFileService
      .uploadAppFileToS3(temporalFile, app.getId(), file.getOriginalFilename());

  //Delete the file
  temporalFile.delete();

  //Now create the domain object for the file and associate it to it's parent
  AppFile appFile = new AppFile();
  appFile.setApp(app);
  appFile.setFileName(file.getOriginalFilename());
  appFile.setS3Key(fileS3Key);
  appFileService.create(appFile);

  //Send a mail to the employees indicating that a new file has been uploaded.
  emailService.sendNewFileUploadNotification(appFile);

  //Create a DTO and return it to the front end
  AppFileDTO appFileDTO = new AppFileDTO();
  appFileDTO.setFileId(appFile.getId());
  appFileDTO.setCreationTimestamp(app.getCreationDate());
  appFileDTO.setFileName(file.getOriginalFilename());

  return appFileDTO;
}

如您所见,在调用将文件上载到S3的服务之后,便调用了发送电子邮件的通知服务。该电子邮件发送完美,这意味着对putObject方法的调用未引发任何异常。

如果我们看一下putObject文档,就会发现:

  

Amazon S3从未存储过部分对象;如果在此通话期间   没有引发异常,整个对象已存储。

这:

  

客户端自动计算文件的校验和。这个   对照另一个计算一次的校验和验证校验和   数据到达Amazon S3,确保数据没有在   通过网络传输。

所以直到现在我都知道:

  • putObject方法不会引发任何异常
  • 我确实知道,因为正在发送邮件,所以在S3引发异常的情况下,它永远不会到达那行代码。
  • S3文档指出,如果上传出现问题,则会引发错误。
  • 文件未存储在存储桶中。

我已经确保在多部分请求中指定了文件名。

任何想法将不胜感激。

1 个答案:

答案 0 :(得分:0)

我看到AWS recommends使用支持标记和重置的流,而FileInputStream不支持。 SDK可能正在尝试通过标记/重置来处理网络问题,在这种情况下,流将抛出“ java.io.IOException:不支持标记/重置”。