我遇到了一个异常,我在测试将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)
我该怎么做才能解决这个问题?我在我的应用程序中使用了与之前相同的代码。
答案 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();