上传到AWS S3时SignatureDoesNotMatch

时间:2017-03-21 09:32:47

标签: java exception amazon-s3 metadata

由于我已经搜索了很长时间以找到错误,我想在这里分享它,以防有人遇到同样的问题: 我已实现以下代码段以将数据上传到S3:

public class S3FileUploadHandler {
  private static final String USER_META_DATA_KEY_MODIFIED = "last-modified";
  private static final SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
  private final AmazonS3Client s3;
  private final TransferManager tm;
  private final String bucketName = "myTestBucket";
  ...

    public void run() {
        File file = ... // retrieve file to upload
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            final String key = ... // some path on S3
            final ObjectMetadata objectMetadata = buildObjectMetadata(file);
            final PutObjectRequest req = new PutObjectRequest(bucketName, key, fis, objectMetadata);
            final Upload upload = tm.upload(req);
            upload.addProgressListener(new MyProgressListener(upload));
            upload.waitForCompletion();
        } catch (final AmazonServiceExceptionase) {
            logger.debug("Couldn't put file {}. AmazonServiceException {}", file, ase);
            logger.error("Couldn't put file {}. AmazonServiceException Error Message: {}", file,    ase.getMessage());
            logger.error("HTTP Status Code: " + ase.getStatusCode());
            logger.error("AWS Error Code:   " + ase.getErrorCode());
            logger.error("Error Type:       " + ase.getErrorType());
            logger.error("Request ID:       " + ase.getRequestId());
        } catch (final Exception e) {
            ...
        } finally {
            if (fis != null) {
                fis.close();
            }
        }
    }

    private ObjectMetadata buildObjectMetadata(final File file) {
        final ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.length());
        final Date lastModifiedDate = new Date(file.lastModified());
        final String dateStr = sdf.format(lastModifiedDate);
        metadata.addUserMetadata(USER_META_DATA_KEY_MODIFIED, dateStr);
        return metadata;
    }
}

代码剪切将文件上传到AWS S3并保留文件的上次修改时间戳,我将此信息设置为用户元数据。

有时上面的代码有效,有时上传会中断,但会出现以下异常:

Couldn't put file C:\Temp\xyz.txt. AmazonServiceException Error Message: The request signature we calculated does not match the signature you provided. Check your key and signing method. (Service: Amazon S3; Status Code: 403; Error Code: SignatureDoesNotMatch; Request ID: B8BC3251B9C1A3F5)
HTTP Status Code: 403
AWS Error Code:   SignatureDoesNotMatch
Error Type:       Client
Request ID:       B8BC3251B9C1A3F5

1 个答案:

答案 0 :(得分:2)

上面代码中的错误是,SimpleDateFormat可能包含非ASCII字符。

E.g。德语区域设置上的最后修改日期可能是

Di Mär 21 10:29:00 MEZ 2017

AWS documentation表示

  

用户定义的元数据是一组键值对。 Amazon S3以小写形式存储用户定义的元数据键。在使用SOAP和基于浏览器的POST上传时,每个键值对在使用REST和UTF-8时必须符合US-ASCII。

AWS可以在这里使用更好的Exception文本,但是根据上述信息,修复很简单:

private static final SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);

...导致(总是)接受的元数据字符串

Tue Mar 21 10:29:00 CET 2017