@@ -3020,6 +3020,7 @@ function multipartUpload(params, callback) {
3020
3020
headers : params . Headers ,
3021
3021
onProgress : params . onProgress ,
3022
3022
body : params . Body || null ,
3023
+ SwitchHost : params . SwitchHost ,
3023
3024
} ,
3024
3025
function ( err , data ) {
3025
3026
if ( err ) return callback ( err ) ;
@@ -3644,9 +3645,7 @@ var getSignHost = function (opt) {
3644
3645
region : useAccelerate ? 'accelerate' : opt . Region ,
3645
3646
} ) ;
3646
3647
var urlHost = url . replace ( / ^ h t t p s ? : \/ \/ ( [ ^ / ] + ) ( \/ .* ) ? $ / , '$1' ) ;
3647
- var standardHostReg = new RegExp ( '^([a-z\\d-]+-\\d+\\.)?(cos|cosv6|ci|pic)\\.([a-z\\d-]+)\\.myqcloud\\.com$' ) ;
3648
- if ( standardHostReg . test ( urlHost ) ) return urlHost ;
3649
- return '' ;
3648
+ return urlHost ;
3650
3649
} ;
3651
3650
3652
3651
// 异步获取签名
@@ -3747,6 +3746,7 @@ function getAuthorizationAsync(params, callback) {
3747
3746
Token : StsData . Token || '' ,
3748
3747
ClientIP : StsData . ClientIP || '' ,
3749
3748
ClientUA : StsData . ClientUA || '' ,
3749
+ SignFrom : 'client' ,
3750
3750
} ;
3751
3751
cb ( null , AuthData ) ;
3752
3752
} ;
@@ -3870,6 +3870,7 @@ function getAuthorizationAsync(params, callback) {
3870
3870
var AuthData = {
3871
3871
Authorization : Authorization ,
3872
3872
SecurityToken : self . options . SecurityToken || self . options . XCosSecurityToken ,
3873
+ SignFrom : 'client' ,
3873
3874
} ;
3874
3875
cb ( null , AuthData ) ;
3875
3876
return AuthData ;
@@ -3878,9 +3879,11 @@ function getAuthorizationAsync(params, callback) {
3878
3879
return '' ;
3879
3880
}
3880
3881
3881
- // 调整时间偏差
3882
+ // 判断当前请求出错时能否重试
3882
3883
function allowRetry ( err ) {
3883
- var allowRetry = false ;
3884
+ var self = this ;
3885
+ var canRetry = false ;
3886
+ var networkError = false ;
3884
3887
var isTimeError = false ;
3885
3888
var serverDate = ( err . headers && ( err . headers . date || err . headers . Date ) ) || ( err . error && err . error . ServerTime ) ;
3886
3889
try {
@@ -3894,6 +3897,7 @@ function allowRetry(err) {
3894
3897
}
3895
3898
} catch ( e ) { }
3896
3899
if ( err ) {
3900
+ // 调整时间偏差
3897
3901
if ( isTimeError && serverDate ) {
3898
3902
var serverTime = Date . parse ( serverDate ) ;
3899
3903
if (
@@ -3902,15 +3906,48 @@ function allowRetry(err) {
3902
3906
) {
3903
3907
console . error ( 'error: Local time is too skewed.' ) ;
3904
3908
this . options . SystemClockOffset = serverTime - Date . now ( ) ;
3905
- allowRetry = true ;
3909
+ canRetry = true ;
3906
3910
}
3907
3911
} else if ( Math . floor ( err . statusCode / 100 ) === 5 ) {
3908
- allowRetry = true ;
3912
+ canRetry = true ;
3909
3913
} else if ( err . code === 'ECONNRESET' ) {
3910
- allowRetry = true ;
3914
+ canRetry = true ;
3915
+ }
3916
+ /**
3917
+ * 归为网络错误
3918
+ * 1、no statusCode
3919
+ * 2、statusCode === 3xx || 4xx || 5xx && no requestId
3920
+ */
3921
+ if ( ! err . statusCode ) {
3922
+ canRetry = self . options . AutoSwitchHost ;
3923
+ networkError = true ;
3924
+ } else {
3925
+ const statusCode = Math . floor ( err . statusCode / 100 ) ;
3926
+ const requestId = err ?. headers && err ?. headers [ 'x-cos-request-id' ] ;
3927
+ if ( [ 3 , 4 , 5 ] . includes ( statusCode ) && ! requestId ) {
3928
+ canRetry = self . options . AutoSwitchHost ;
3929
+ networkError = true ;
3930
+ }
3911
3931
}
3912
3932
}
3913
- return allowRetry ;
3933
+ return { canRetry, networkError } ;
3934
+ }
3935
+
3936
+ /**
3937
+ * requestUrl:请求的url,用于判断是否cos主域名,true才切
3938
+ * clientCalcSign:是否客户端计算签名,服务端返回的签名不能切,true才切
3939
+ * networkError:是否未知网络错误,true才切
3940
+ * */
3941
+ function canSwitchHost ( { requestUrl, clientCalcSign, networkError } ) {
3942
+ if ( ! this . options . AutoSwitchHost ) return false ;
3943
+ if ( ! requestUrl ) return false ;
3944
+ if ( ! clientCalcSign ) return false ;
3945
+ if ( ! networkError ) return false ;
3946
+ const commonReg = / ^ h t t p s ? : \/ \/ [ ^ \/ ] * \. c o s \. [ ^ \/ ] * \. m y q c l o u d \. c o m ( \/ .* ) ? $ / ;
3947
+ const accelerateReg = / ^ h t t p s ? : \/ \/ [ ^ \/ ] * \. c o s \. a c c e l e r a t e \. m y q c l o u d \. c o m ( \/ .* ) ? $ / ;
3948
+ // 当前域名是cos主域名才切换
3949
+ const isCommonCosHost = commonReg . test ( requestUrl ) && ! accelerateReg . test ( requestUrl ) ;
3950
+ return isCommonCosHost ;
3914
3951
}
3915
3952
3916
3953
// 获取签名并发起请求
@@ -3937,6 +3974,11 @@ function submitRequest(params, callback) {
3937
3974
params . SignHost || getSignHost . call ( this , { Bucket : params . Bucket , Region : params . Region , Url : params . url } ) ;
3938
3975
var next = function ( tryTimes ) {
3939
3976
var oldClockOffset = self . options . SystemClockOffset ;
3977
+ if ( params . SwitchHost ) {
3978
+ // 更换要签的host
3979
+ SignHost = SignHost . replace ( / m y q c l o u d .c o m / , 'tencentcos.cn' ) ;
3980
+ }
3981
+
3940
3982
getAuthorizationAsync . call (
3941
3983
self ,
3942
3984
{
@@ -3951,18 +3993,20 @@ function submitRequest(params, callback) {
3951
3993
ResourceKey : params . ResourceKey ,
3952
3994
Scope : params . Scope ,
3953
3995
ForceSignHost : self . options . ForceSignHost ,
3996
+ SwitchHost : params . SwitchHost ,
3954
3997
} ,
3955
3998
function ( err , AuthData ) {
3956
3999
if ( err ) return callback ( err ) ;
3957
4000
params . AuthData = AuthData ;
3958
4001
_submitRequest . call ( self , params , function ( err , data ) {
3959
- if (
3960
- err &&
3961
- ! ( params . body && params . body . pipe ) &&
3962
- ! params . outputStream &&
3963
- tryTimes < 2 &&
3964
- ( oldClockOffset !== self . options . SystemClockOffset || allowRetry . call ( self , err ) )
3965
- ) {
4002
+ let canRetry = false ;
4003
+ let networkError = false ;
4004
+ if ( err ) {
4005
+ const info = allowRetry . call ( self , err ) ;
4006
+ canRetry = info . canRetry || oldClockOffset !== self . options . SystemClockOffset ;
4007
+ networkError = info . networkError ;
4008
+ }
4009
+ if ( err && ! ( params . body && params . body . pipe ) && ! params . outputStream && tryTimes < 2 && canRetry ) {
3966
4010
if ( params . headers ) {
3967
4011
delete params . headers . Authorization ;
3968
4012
delete params . headers [ 'token' ] ;
@@ -3971,8 +4015,23 @@ function submitRequest(params, callback) {
3971
4015
params . headers [ 'x-cos-security-token' ] && delete params . headers [ 'x-cos-security-token' ] ;
3972
4016
params . headers [ 'x-ci-security-token' ] && delete params . headers [ 'x-ci-security-token' ] ;
3973
4017
}
4018
+ // 进入重试逻辑时 需判断是否需要切换cos备用域名
4019
+ const switchHost = canSwitchHost . call ( self , {
4020
+ requestUrl : err ?. url || '' ,
4021
+ clientCalcSign : AuthData ?. SignFrom === 'client' ,
4022
+ networkError,
4023
+ } ) ;
4024
+ params . SwitchHost = switchHost ;
3974
4025
next ( tryTimes + 1 ) ;
3975
4026
} else {
4027
+ if ( err && params . Action === 'name/cos:UploadPart' ) {
4028
+ const switchHost = canSwitchHost . call ( self , {
4029
+ requestUrl : err ?. url || '' ,
4030
+ clientCalcSign : AuthData ?. SignFrom === 'client' ,
4031
+ networkError,
4032
+ } ) ;
4033
+ err . switchHost = switchHost ;
4034
+ }
3976
4035
callback ( err , data ) ;
3977
4036
}
3978
4037
} ) ;
@@ -4018,6 +4077,10 @@ function _submitRequest(params, callback) {
4018
4077
region : region ,
4019
4078
object : object ,
4020
4079
} ) ;
4080
+ if ( params . SwitchHost ) {
4081
+ // 更换请求的url
4082
+ url = url . replace ( / m y q c l o u d .c o m / , 'tencentcos.cn' ) ;
4083
+ }
4021
4084
if ( params . action ) {
4022
4085
url = url + '?' + params . action ;
4023
4086
}
@@ -4113,6 +4176,8 @@ function _submitRequest(params, callback) {
4113
4176
retResponse && retResponse . statusCode && ( attrs . statusCode = retResponse . statusCode ) ;
4114
4177
retResponse && retResponse . headers && ( attrs . headers = retResponse . headers ) ;
4115
4178
if ( err ) {
4179
+ opt . url && ( attrs . url = opt . url ) ;
4180
+ opt . method && ( attrs . method = opt . method ) ;
4116
4181
err = util . extend ( err || { } , attrs ) ;
4117
4182
callback ( err , null ) ;
4118
4183
} else {
0 commit comments