Skip to content

Commit 1b8a6e5

Browse files
authored
Merge pull request #15 from dt3310321/s3
S3 兼容
2 parents 9ec5a98 + 8e6200f commit 1b8a6e5

File tree

3 files changed

+77
-20
lines changed

3 files changed

+77
-20
lines changed

README.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,19 @@ __________
2222

2323
使用python sdk,参照https://github.com/tencentyun/cos-python-sdk-v5/blob/master/qcloud_cos/test.py
2424

25+
cos最新可用地域,参照https://www.qcloud.com/document/product/436/6224
26+
2527
.. code:: python
2628
27-
# 设置用户属性, 包括appid, secret_id和secret_key
29+
# 设置用户属性, 包括appid, secret_id, secret_key, region
2830
appid = 100000 # 替换为用户的appid
2931
secret_id = u'xxxxxxxx' # 替换为用户的secret_id
3032
secret_key = u'xxxxxxx' # 替换为用户的secret_key
31-
  region = "cn-north"       # 替换为用户的region,目前可以为 cn-east/cn-south/cn-north/cn-southwest,分别对应于上海,广州,天津,西南园区
32-
   config = CosConfig(Appid=appid, Region=region, Access_id=secret_id, Access_key=secret_key, Token='')  #获取配置对象 使用临时秘钥需要传入Token,默认为空
33-
   client = CosS3Client(config)                                                               #获取客户端对象
33+
  region = "ap-beiging-1"    # 替换为用户的region
34+
token = '' # 使用临时秘钥需要传入Token,默认为空,可不填
35+
config = CosConfig(Appid=appid, Region=region, Access_id=secret_id, Access_key=secret_key, Token=token) #获取配置对象
36+
client = CosS3Client(config) #获取客户端对象
37+
3438
3539
############################################################################
3640
# 文件操作 #
@@ -99,14 +103,14 @@ __________
99103
Key='mutilpartfile.txt',
100104
UploadId=uploadid
101105
)
102-
lst = response['Part']
106+
lst = response['Part'] # list_parts最大数量为1000
103107
104108
# 10. 完成分片上传
105109
response = client.complete_multipart_upload(
106110
Bucket='test01',
107111
Key='multipartfile.txt',
108112
UploadId=uploadid,
109-
MultipartUpload={'Part': lst}
113+
MultipartUpload={'Part': lst} # 超过1000个分块,请本地保存分块信息,再complete
110114
)
111115
112116

qcloud_cos/cos_client.py

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,31 @@
2525
sys.setdefaultencoding('utf-8')
2626
maplist = {
2727
'ContentLength': 'Content-Length',
28-
'ContentType': 'Content-Type',
2928
'ContentMD5': 'Content-MD5',
29+
'ContentType': 'Content-Type',
3030
'CacheControl': 'Cache-Control',
3131
'ContentDisposition': 'Content-Disposition',
3232
'ContentEncoding': 'Content-Encoding',
33+
'ContentLanguage': 'Content-Language',
3334
'Expires': 'Expires',
35+
'ResponseContentType': 'response-content-type',
36+
'ResponseContentLanguage': 'response-content-language',
37+
'ResponseExpires': 'response-expires',
38+
'ResponseCacheControl': 'response-cache-control',
39+
'ResponseContentDisposition': 'response-content-disposition',
40+
'ResponseContentEncoding': 'response-content-encoding',
3441
'Metadata': 'Metadata',
3542
'ACL': 'x-cos-acl',
3643
'GrantFullControl': 'x-cos-grant-full-control',
3744
'GrantWrite': 'x-cos-grant-write',
3845
'GrantRead': 'x-cos-grant-read',
3946
'StorageClass': 'x-cos-storage-class',
40-
'EncodingType': 'encoding-type'
47+
'Range': 'Range',
48+
'IfMatch': 'If-Match',
49+
'IfNoneMatch': 'If-None-Match',
50+
'IfModifiedSince': 'If-Modified-Since',
51+
'IfUnmodifiedSince': 'If-Unmodified-Since',
52+
'VersionId': 'x-cos-version-id',
4153
}
4254

4355

@@ -109,11 +121,39 @@ def mapped(headers):
109121
return _headers
110122

111123

124+
def format_region(region):
125+
if region.find('cos.') != -1:
126+
return region # 传入cos.ap-beijing-1这样显示加上cos.的region
127+
if region == 'cn-north' or region == 'cn-south' or region == 'cn-east' or region == 'cn-south-2' or region == 'cn-southwest' or region == 'sg':
128+
return region # 老域名不能加cos.
129+
# 支持v4域名映射到v5
130+
if region == 'cossh':
131+
return 'cos.ap-shanghai'
132+
if region == 'cosgz':
133+
return 'cos.ap-guangzhou'
134+
if region == 'cosbj':
135+
return 'cos.ap-beijing'
136+
if region == 'costj':
137+
return 'cos.ap-beijing-1'
138+
if region == 'coscd':
139+
return 'cos.ap-chengdu'
140+
if region == 'cossgp':
141+
return 'cos.ap-singapore'
142+
if region == 'coshk':
143+
return 'cos.ap-hongkong'
144+
if region == 'cosca':
145+
return 'cos.na-toronto'
146+
if region == 'cosger':
147+
return 'cos.eu-frankfurt'
148+
149+
return 'cos.' + region # 新域名加上cos.
150+
151+
112152
class CosConfig(object):
113153
"""config类,保存用户相关信息"""
114154
def __init__(self, Appid, Region, Access_id, Access_key, Token=None):
115155
self._appid = Appid
116-
self._region = Region
156+
self._region = format_region(Region)
117157
self._access_id = Access_id
118158
self._access_key = Access_key
119159
self._token = Token
@@ -126,14 +166,14 @@ def uri(self, bucket, path=None):
126166
if path:
127167
if path[0] == '/':
128168
path = path[1:]
129-
url = u"http://{bucket}-{uid}.cos.{region}.myqcloud.com/{path}".format(
169+
url = u"http://{bucket}-{uid}.{region}.myqcloud.com/{path}".format(
130170
bucket=to_unicode(bucket),
131171
uid=self._appid,
132172
region=self._region,
133173
path=to_unicode(path)
134174
)
135175
else:
136-
url = u"http://{bucket}-{uid}.cos.{region}.myqcloud.com".format(
176+
url = u"http://{bucket}-{uid}.{region}.myqcloud.com".format(
137177
bucket=to_unicode(bucket),
138178
uid=self._appid,
139179
region=self._region
@@ -246,7 +286,7 @@ def get_presigned_download_url(self, Bucket, Key, Expired=300):
246286
"""生成预签名的下载url"""
247287
url = self._conf.uri(bucket=Bucket, path=Key)
248288
sign = self.get_auth(Method='GET', Bucket=Bucket, Key=Key, Expired=300)
249-
url = url + '?sign=' + urllib.quote(sign)
289+
url = urllib.quote(url.encode('utf8'), ':/') + '?sign=' + urllib.quote(sign)
250290
return url
251291

252292
def delete_object(self, Bucket, Key, **kwargs):
@@ -311,6 +351,11 @@ def copy_object(self, Bucket, Key, CopySource, CopyStatus='Copy', **kwargs):
311351
def create_multipart_upload(self, Bucket, Key, **kwargs):
312352
"""创建分片上传,适用于大文件上传"""
313353
headers = mapped(kwargs)
354+
if 'Metadata' in headers.keys():
355+
for i in headers['Metadata'].keys():
356+
headers[i] = headers['Metadata'][i]
357+
headers.pop('Metadata')
358+
314359
url = self._conf.uri(bucket=Bucket, path=Key+"?uploads")
315360
logger.info("create multipart upload, url=:{url} ,headers=:{headers}".format(
316361
url=url,
@@ -374,18 +419,25 @@ def abort_multipart_upload(self, Bucket, Key, UploadId, **kwargs):
374419
headers=headers)
375420
return None
376421

377-
def list_parts(self, Bucket, Key, UploadId, **kwargs):
422+
def list_parts(self, Bucket, Key, UploadId, EncodingType='url', MaxParts=1000, PartNumberMarker=0, **kwargs):
378423
"""列出已上传的分片"""
379424
headers = mapped(kwargs)
380-
url = self._conf.uri(bucket=Bucket, path=Key+"?uploadId={UploadId}".format(UploadId=UploadId))
425+
params = {
426+
'uploadId': UploadId,
427+
'part-number-marker': PartNumberMarker,
428+
'max-parts': MaxParts,
429+
'encoding-type': EncodingType}
430+
431+
url = self._conf.uri(bucket=Bucket, path=Key)
381432
logger.info("list multipart upload, url=:{url} ,headers=:{headers}".format(
382433
url=url,
383434
headers=headers))
384435
rt = self.send_request(
385436
method='GET',
386437
url=url,
387438
auth=CosS3Auth(self._conf._access_id, self._conf._access_key),
388-
headers=headers)
439+
headers=headers,
440+
params=params)
389441
data = xml_to_dict(rt.text)
390442
if 'Part' in data.keys() and isinstance(data['Part'], dict): # 只有一个part,将dict转为list,保持一致
391443
lst = []
@@ -455,7 +507,7 @@ def delete_bucket(self, Bucket, **kwargs):
455507
headers=headers)
456508
return None
457509

458-
def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="", **kwargs):
510+
def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="", EncodingType="url", **kwargs):
459511
"""获取文件列表"""
460512
headers = mapped(kwargs)
461513
url = self._conf.uri(bucket=Bucket)
@@ -466,7 +518,8 @@ def list_objects(self, Bucket, Delimiter="", Marker="", MaxKeys=1000, Prefix="",
466518
'delimiter': Delimiter,
467519
'marker': Marker,
468520
'max-keys': MaxKeys,
469-
'prefix': Prefix}
521+
'prefix': Prefix,
522+
'encoding-type': EncodingType}
470523
rt = self.send_request(
471524
method='GET',
472525
url=url,

qcloud_cos/test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def tearDown():
3939
def Test():
4040
conf = CosConfig(
4141
Appid="1252448703",
42-
Region="cn-north",
42+
Region="ap-beijing-1",
4343
Access_id=ACCESS_ID,
4444
Access_key=ACCESS_KEY
4545
)
@@ -53,7 +53,7 @@ def Test():
5353
print "Test Get Presigned Download URL "
5454
url = client.get_presigned_download_url(
5555
Bucket=test_bucket,
56-
Key='test.txt'
56+
Key='中文.txt'
5757
)
5858
print url
5959

@@ -81,7 +81,7 @@ def Test():
8181
except CosServiceError as e:
8282
print_error_msg(e)
8383

84-
special_file_name = "对象()*'/. 存![]^&*~储{|}~()"
84+
special_file_name = "中文" + "→↓←→↖↗↙↘! \"#$%&'()*+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
8585
print "Test Put Object Contains Special Characters " + special_file_name
8686
response = client.put_object(
8787
Bucket=test_bucket,

0 commit comments

Comments
 (0)