Skip to content

Commit c58dbe6

Browse files
authored
Merge pull request #259 from l-iberty/master
重试时domain切换逻辑修改
2 parents 838ffc5 + 2b77b1c commit c58dbe6

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

qcloud_cos/cos_client.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class CosConfig(object):
4343
def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token=None, CredentialInstance=None, Scheme=None, Timeout=None,
4444
Access_id=None, Access_key=None, Secret_id=None, Secret_key=None, Endpoint=None, IP=None, Port=None,
4545
Anonymous=None, UA=None, Proxies=None, Domain=None, ServiceDomain=None, KeepAlive=True, PoolConnections=10,
46-
PoolMaxSize=10, AllowRedirects=False, SignHost=True, EndpointCi=None, EndpointPic=None, EnableOldDomain=True, EnableInternalDomain=True, SignParams=True):
46+
PoolMaxSize=10, AllowRedirects=False, SignHost=True, EndpointCi=None, EndpointPic=None, EnableOldDomain=True, EnableInternalDomain=True, SignParams=True,
47+
AutoSwitchDomainOnRetry=True):
4748
"""初始化,保存用户的信息
4849
4950
:param Appid(string): 用户APPID.
@@ -74,6 +75,7 @@ def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token
7475
:param EnableOldDomain(bool): 是否使用旧的myqcloud.com域名访问COS
7576
:param EnableInternalDomain(bool): 是否使用内网域名访问COS
7677
:param SignParams(bool): 是否将请求参数算入签名
78+
:param AutoSwitchDomainOnRetry(bool): 重试请求时是否自动切换域名
7779
"""
7880
self._appid = to_unicode(Appid)
7981
self._token = to_unicode(Token)
@@ -98,6 +100,7 @@ def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token
98100
self._enable_old_domain = EnableOldDomain
99101
self._enable_internal_domain = EnableInternalDomain
100102
self._sign_params = SignParams
103+
self._auto_switch_domain_on_retry = AutoSwitchDomainOnRetry
101104

102105
if self._domain is None:
103106
self._endpoint = format_endpoint(Endpoint, Region, u'cos.', EnableOldDomain, EnableInternalDomain)
@@ -347,6 +350,7 @@ def send_request(self, method, url, bucket, timeout=30, cos_request=True, ci_req
347350
kwargs['headers'] = format_values(kwargs['headers'])
348351

349352
file_position = None
353+
domain_switched = False # 重试时如果要切换域名, 只切换一次
350354
if 'data' in kwargs:
351355
body = kwargs['data']
352356
if hasattr(body, 'tell') and hasattr(body, 'seek') and hasattr(body, 'read'):
@@ -376,13 +380,25 @@ def send_request(self, method, url, bucket, timeout=30, cos_request=True, ci_req
376380
break
377381
else:
378382
if j < self._retry and client_can_retry(file_position, **kwargs):
383+
if not domain_switched and self._conf._auto_switch_domain_on_retry and self._conf._ip is None:
384+
# 重试时切换域名
385+
logger.debug("switch hostname, url before: " + url)
386+
url = switch_hostname_for_url(url)
387+
domain_switched = True
388+
logger.debug("switch hostname, url after: " + url)
379389
continue
380390
else:
381391
break
382392
except Exception as e: # 捕获requests抛出的如timeout等客户端错误,转化为客户端错误
383393
logger.exception('url:%s, retry_time:%d exception:%s' % (url, j, str(e)))
384394
if j < self._retry and (isinstance(e, ConnectionError) or isinstance(e, Timeout)): # 只重试网络错误
385395
if client_can_retry(file_position, **kwargs):
396+
if not domain_switched and self._conf._auto_switch_domain_on_retry and self._conf._ip is None:
397+
# 重试时切换域名
398+
logger.debug("switch hostname, url before: " + url)
399+
url = switch_hostname_for_url(url)
400+
domain_switched = True
401+
logger.debug("switch hostname, url after: " + url)
386402
continue
387403
raise CosClientError(str(e))
388404

@@ -3447,7 +3463,7 @@ def _upload_part(self, bucket, key, local_path, offset, size, part_num, uploadid
34473463
fp.seek(offset, 0)
34483464
data = fp.read(size)
34493465
rt = self.upload_part(bucket, key, data, part_num, uploadid, enable_md5, **kwargs)
3450-
lower_rt = { k.lower():v for k,v in rt.items() }
3466+
lower_rt = dict([(k.lower(), v) for k, v in rt.items()])
34513467
md5_lst.append({'PartNumber': part_num, 'ETag': lower_rt['etag']})
34523468
if progress_callback:
34533469
progress_callback.report(size)

qcloud_cos/cos_comm.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding=utf-8
22

33
from six import text_type, binary_type, string_types
4-
from six.moves.urllib.parse import quote, unquote
4+
from six.moves.urllib.parse import quote, unquote, urlparse
55
import hashlib
66
import base64
77
import os
@@ -244,6 +244,32 @@ def format_endpoint(endpoint, region, module, EnableOldDomain, EnableInternalDom
244244
else:
245245
return None
246246

247+
def switch_hostname(host):
248+
"""将cos默认域名的.myqcloud.com后缀替换为.tencentcos.cn"""
249+
if not host:
250+
raise CosClientError("Host is required not empty!")
251+
252+
# *.cos.*-*.myqcloud.com
253+
if re.match(r'^.*\.cos\..*\-.*\.myqcloud\.com$', host):
254+
host = host[:-len(".myqcloud.com")] + ".tencentcos.cn"
255+
256+
return host
257+
258+
def switch_hostname_for_url(url):
259+
if not url:
260+
raise CosClientError("Url is required not empty!")
261+
262+
url_parsed = urlparse(url)
263+
if url_parsed.hostname is not None:
264+
host = url_parsed.hostname
265+
new_host = switch_hostname(host)
266+
if host != new_host:
267+
new_url = url.replace(host, new_host)
268+
return new_url
269+
270+
"""返回原始url"""
271+
return url
272+
247273

248274
def format_region(region, module, EnableOldDomain, EnableInternalDomain):
249275
"""格式化地域"""

ut/test.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from qcloud_cos.cos_encryption_client import CosEncryptionClient
1616
from qcloud_cos.crypto import AESProvider
1717
from qcloud_cos.crypto import RSAProvider
18-
from qcloud_cos.cos_comm import CiDetectType, get_md5, to_bytes
18+
from qcloud_cos.cos_comm import CiDetectType, get_md5, to_bytes, switch_hostname_for_url
1919

2020
SECRET_ID = os.environ["COS_SECRET_ID"]
2121
SECRET_KEY = os.environ["COS_SECRET_KEY"]
@@ -3562,6 +3562,37 @@ def test_check_multipart_upload():
35623562
UploadId=uploadId
35633563
)
35643564

3565+
def test_switch_hostname_for_url():
3566+
url = "https://example-125000000.cos.ap-chengdu.myqcloud.com/123"
3567+
res = switch_hostname_for_url(url)
3568+
exp = "https://example-125000000.cos.ap-chengdu.tencentcos.cn/123"
3569+
assert res == exp
3570+
3571+
url = "https://example-125000000.cos.ap-chengdu.tencentcos.cn/123"
3572+
res = switch_hostname_for_url(url)
3573+
exp = "https://example-125000000.cos.ap-chengdu.tencentcos.cn/123"
3574+
assert res == exp
3575+
3576+
url = "https://cos.ap-chengdu.myqcloud.com/123"
3577+
res = switch_hostname_for_url(url)
3578+
exp = "https://cos.ap-chengdu.myqcloud.com/123"
3579+
assert res == exp
3580+
3581+
url = "https://service.cos.myqcloud.com/123"
3582+
res = switch_hostname_for_url(url)
3583+
exp = "https://service.cos.myqcloud.com/123"
3584+
assert res == exp
3585+
3586+
url = "https://example-125000000.file.myqcloud.com/123"
3587+
res = switch_hostname_for_url(url)
3588+
exp = "https://example-125000000.file.myqcloud.com/123"
3589+
assert res == exp
3590+
3591+
try:
3592+
switch_hostname_for_url('')
3593+
except Exception as e:
3594+
print(e)
3595+
35653596
if __name__ == "__main__":
35663597
setUp()
35673598
"""

0 commit comments

Comments
 (0)