例外情况“您指定的Content-MD5与我们收到的内容不符”

时间:2016-03-23 13:18:31

标签: amazon-s3 aws-sdk

我遇到了一个异常,我在测试将ec2中的文件上传到s3的应用程序时从未遇到过。内容是:

Exception in thread "Thread-1" com.amazonaws.services.s3.model.AmazonS3Exception: The Content-MD5 you specified did not match what we received. (Service: Amazon S3; Status Code: 400; Error Code: BadDigest; Request ID: 972CB8E04388AB20), S3 Extended Request ID: T7bmFnQ2RlGWlJD+aGYfTy97XZw88pbQrwNB8YCezSjyq6O2joxHRP/6ko+Q2zZeGewkw4x/90k=
    at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1383)
    at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:902)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:607)
    at com.amazonaws.http.AmazonHttpClient.doExecute(AmazonHttpClient.java:376)
    at com.amazonaws.http.AmazonHttpClient.executeWithTimer(AmazonHttpClient.java:338)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:287)
    at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3676)
    at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1439)
    at com.amazonaws.services.s3.transfer.internal.UploadCallable.uploadInOneChunk(UploadCallable.java:131)
    at com.amazonaws.services.s3.transfer.internal.UploadCallable.call(UploadCallable.java:123)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.call(UploadMonitor.java:139)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.call(UploadMonitor.java:47)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

我该怎么做才能解决这个问题?我在我的应用程序中使用了与之前相同的代码。

5 个答案:

答案 0 :(得分:11)

我想我已经解决了我的问题。我终于发现我的一些文件在上传过程中确实发生了变化。由于该文件是由另一个线程生成的,因此上传和生成是同时完成的。该文件不能立即生成,并且在生成文件期间,可能同时上传,文件在上传过程中实际发生了变化。

文件的md5是在AmazonS3Client上传开始时创建的,然后整个文件上传到S3,此时,文件与开头上传的文件不同,所以md5实际上已经改变了。我将程序修改为单线程程序,问题再也没有出现过。

答案 1 :(得分:6)

遇到此问题的另一个原因是运行此类代码(python)

with open(filename, 'r') as fd:
     self._bucket1.put_object(Key=key, Body=fd)
     self._bucket2.put_object(Key=key, Body=fd)

在这种情况下,文件对象(fd)在到达第3行时指向文件的末尾,因此我们将得到“Content MD5”错误,为了避免它,我们需要指向文件阅读器回到文件中的起始位置

with open(filename, 'r') as fd:
     bucket1.put_object(Key=key, Body=fd)
     fd.seek(0)
     bucket2.put_object(Key=key, Body=fd)

这样我们就不会得到上述的Boto错误。

答案 2 :(得分:0)

FWIW,我设法找到了一种完全不同的触发此问题的方法,这需要不同的解决方案。

事实证明,如果您决定明确地将ObjectMetadata分配给PutObjectRequest,例如指定cacheControl设置或contentType,则AWS开发工具包将{{ 1}}实例以存储它为放置请求计算的MD5。这意味着,如果您要放置多个对象,您认为所有对象都应分配有相同的元数据,则仍然需要为每个ObjectMetadata创建一个新的ObjectMetadata实例。如果您不这样做,那么它将重用从上一个放置请求计算出的MD5,并在尝试放置的第二个对象上收到MD5不匹配错误。

因此,明确地说,在第二次迭代中执行类似的操作将失败:

PutObjectRequest

您需要这样做:

ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("text/html");
for(Put obj: thingsToPut)
{
    PutObjectRequest por = 
        new PutObjectRequest(bucketName, obj.s3Key, obj.file);
    por = por.withMetadata(metadata);
    PutObjectResult res = s3.putObject(por);
}

答案 3 :(得分:0)

我也遇到了这个问题。我如何解决这个问题: 我有一个处理AWS SQS消息的微服务。每个消息将创建多个临时文件,这些临时文件必须上载到S3。 问题是临时文件使用固定名称命名,而没有添加任何盐。 因此,在两条消息之间,可以重写要上载的原始文件。 我在文件名中添加了随机盐(可以是uuid或当前时间,以毫秒为单位,具体取决于您想要的名称),之后文件不会被覆盖并成功上传到S3

答案 4 :(得分:0)

对我来说,我在执行 ContentLength 时在参数中使用了 upload。当它被注释掉时,它工作得很好。

const params = {
  Bucket: "",
  ContentType: "application/json",
  Key: "filename.json",
  // ContentLength: body.length,   <--- what I have commented out
  Body: body
};
await s3.upload(params).promise();