我正在使用
python-swiftclient
和 zipfile
编写 Python 脚本,以将文件压缩并上传到 Openstack 对象存储的 Swift API 端点。我将压缩数据作为 io.BytesIO
对象存储在内存中。
代码片段:
arc_name = 'test.zip'
zip_buffer = io.BytesIO()
with open zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, True) as zip_file:
for file in files:
with open(file, 'rb') as src_file:
zip_file.writestr(arc_name, src_file.read())
...
zip_data = zip_buffer.getvalue()
checksum_base64 = base64.b64encode(hashlib.md5(zip_data).digest()).decode()
swift_conn = swiftclient.Connection(<creds>)
container_name = 'swift-test'
swift_conn.put_object(container=container_name, contents=zip_data, content_type=None, obj=arc_name, etag=checksum_base64)
错误是:
swiftclient.exceptions.ClientException: Object PUT failed: https://..../swift/v1/swift-test/test.zip 422 Unprocessable Entity
从其他 HTTP 422 错误问题来看,我的想法是问题是
content_type
(MIME 类型)。我尝试过 'application/zip'
和 'multipart/mixed'
但总是看到相同的错误。
如果其他 MIME 类型更合适,或者我遗漏了其他内容,我将不胜感激。
我发现了这个问题,并且
content_type
是一个转移注意力的话题。问题是etag
。
checksum_hash = hashlib.md5(zip_data)
checksum_string = checksum_hash.hexdigest()
checksum_base64 = base64.b64encode(checksum_hash.digest()).decode()
swift_conn.put_object(container=container_name,
contents=zip_data,
content_type=None,
obj=arc_name,
etag=checksum_base64) # fails
swift_conn.put_object(container=container_name,
contents=zip_data,
content_type=None,
obj=arc_name,
etag=checksum_string) # works
也适用于
content_type='multipart/mixed'
,建议与 zip 存档一起使用。因此上传只是因为校验和不匹配而被拒绝。
我错误使用
checksum_base64
的原因是之前来自boto3
,put_object
函数调用使用了ContentMD5=checksum_base64
。