介绍
腾迅云提供 COS 服务,专门用于存储静态文件。
之前有试过使用 COSCMD 工具 部署文件到对象存储 CDN - 狂飙,但是工具最大的问题在于每次调用都会检查要上传目录的所有文件,每个文件都会发送一个 HEAD 请求来查看是否需要更新,校验时长会随着文件数量线性增加。
环境
- Windows 10 21H2
- Python 3.10
- PyCharm 2021.3
调试
上传文件后需要使用官方的 GUI 客户端 COSBrowser 构验文件属性,确认文件是否正确上传。
本地缓存
本地上传时一般都会指定将整个资源根目录上传,里面大部分文件可能都是上传过的。为了减少不必要的检查,需要实现一层本地缓存,可以在缓存中保存文件的相对路径、长度与最后修改时间,每次上传前检查。
远程校验
- 远程上传文件前先使用 HEAD 接口获取文件信息
- 文件存在则比对本地文件 MD5 与远程文件 MD5
- 相同则认为文件就是要上传的版本,跳过上传
- 不同则需要先删除文件再上传
- 文件不存在则上传
- 上传时要设置校验值,推荐使用比较通用的 MD5
数据在客户端和服务器间传输时可能会出现错误,COS 可以通过 MD5 校验的方式保证上传数据的完整性,只有当 COS 服务器接收到的数据 MD5 校验值与用户设置的 MD5 校验值一致时,数据才可上传成功。
COS 里每个对象对应一个 ETag,ETag 是对象被创建时对象内容的信息标识,但 ETag 不一定等同于对象内容的 MD5 校验值,因此不能通过 ETag 来校验下载对象与原对象是否一致,但用户可使用自定义对象元数据(x-cos-meta-*)来实现下载对象与原对象的一致性校验。
腾迅云官方文档介绍了如何实现 MD5 校验,因此需要本地先算出 MD5,存储到自定义的 Key 中供后续使用。
SDK
腾迅云官方提供了各种语言的 SDK,这里使用 Python SDK 实现上传:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
def cos_upload_file(thread_pool, cos_client, bucket, local_path, remote_path):
local_md5, local_md5_base64 = calculate_md5(local_path)
exists = False
try:
exist_response = cos_client.head_object(Bucket=bucket, Key=remote_path)
remote_md5 = exist_response[metadata_md5_key]
if local_md5 == remote_md5:
exists = True
else:
delete_response = cos_client.delete_object(Bucket=bucket, Key=remote_path)
if 'x-cos-request-id' not in delete_response:
print(f'{remote_path} delete fail and md5 {remote_md5} different local md5 {local_md5}')
raise Exception(f'{remote_path} delete fail and md5 {remote_md5} different local md5 {local_md5}')
except CosServiceError as e:
if e.get_status_code() == 404:
exists = False
else:
print("Error happened, upload it again.")
if not exists:
print(f'Upload {local_path}')
metadata = {
metadata_md5_key: local_md5,
}
thread_pool.add_task(cos_client.upload_file, bucket, remote_path, local_path,
ContentMD5=local_md5_base64, Metadata=metadata)
|
集成
需要手工构建出来不同的情况来校验整个上传流程是否正确。强烈建议将所有情况与分支都测试到,因为后续在生产环境中使用出问题调试就比较麻烦。