@@ -3020,6 +3020,7 @@ function multipartUpload(params, callback) {
30203020 headers : params . Headers ,
30213021 onProgress : params . onProgress ,
30223022 body : params . Body || null ,
3023+ SwitchHost : params . SwitchHost ,
30233024 } ,
30243025 function ( err , data ) {
30253026 if ( err ) return callback ( err ) ;
@@ -3644,9 +3645,7 @@ var getSignHost = function (opt) {
36443645 region : useAccelerate ? 'accelerate' : opt . Region ,
36453646 } ) ;
36463647 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 ;
36503649} ;
36513650
36523651// 异步获取签名
@@ -3747,6 +3746,7 @@ function getAuthorizationAsync(params, callback) {
37473746 Token : StsData . Token || '' ,
37483747 ClientIP : StsData . ClientIP || '' ,
37493748 ClientUA : StsData . ClientUA || '' ,
3749+ SignFrom : 'client' ,
37503750 } ;
37513751 cb ( null , AuthData ) ;
37523752 } ;
@@ -3870,6 +3870,7 @@ function getAuthorizationAsync(params, callback) {
38703870 var AuthData = {
38713871 Authorization : Authorization ,
38723872 SecurityToken : self . options . SecurityToken || self . options . XCosSecurityToken ,
3873+ SignFrom : 'client' ,
38733874 } ;
38743875 cb ( null , AuthData ) ;
38753876 return AuthData ;
@@ -3878,9 +3879,11 @@ function getAuthorizationAsync(params, callback) {
38783879 return '' ;
38793880}
38803881
3881- // 调整时间偏差
3882+ // 判断当前请求出错时能否重试
38823883function allowRetry ( err ) {
3883- var allowRetry = false ;
3884+ var self = this ;
3885+ var canRetry = false ;
3886+ var networkError = false ;
38843887 var isTimeError = false ;
38853888 var serverDate = ( err . headers && ( err . headers . date || err . headers . Date ) ) || ( err . error && err . error . ServerTime ) ;
38863889 try {
@@ -3894,6 +3897,7 @@ function allowRetry(err) {
38943897 }
38953898 } catch ( e ) { }
38963899 if ( err ) {
3900+ // 调整时间偏差
38973901 if ( isTimeError && serverDate ) {
38983902 var serverTime = Date . parse ( serverDate ) ;
38993903 if (
@@ -3902,15 +3906,48 @@ function allowRetry(err) {
39023906 ) {
39033907 console . error ( 'error: Local time is too skewed.' ) ;
39043908 this . options . SystemClockOffset = serverTime - Date . now ( ) ;
3905- allowRetry = true ;
3909+ canRetry = true ;
39063910 }
39073911 } else if ( Math . floor ( err . statusCode / 100 ) === 5 ) {
3908- allowRetry = true ;
3912+ canRetry = true ;
39093913 } 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+ }
39113931 }
39123932 }
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 ;
39143951}
39153952
39163953// 获取签名并发起请求
@@ -3937,6 +3974,11 @@ function submitRequest(params, callback) {
39373974 params . SignHost || getSignHost . call ( this , { Bucket : params . Bucket , Region : params . Region , Url : params . url } ) ;
39383975 var next = function ( tryTimes ) {
39393976 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+
39403982 getAuthorizationAsync . call (
39413983 self ,
39423984 {
@@ -3951,18 +3993,20 @@ function submitRequest(params, callback) {
39513993 ResourceKey : params . ResourceKey ,
39523994 Scope : params . Scope ,
39533995 ForceSignHost : self . options . ForceSignHost ,
3996+ SwitchHost : params . SwitchHost ,
39543997 } ,
39553998 function ( err , AuthData ) {
39563999 if ( err ) return callback ( err ) ;
39574000 params . AuthData = AuthData ;
39584001 _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 ) {
39664010 if ( params . headers ) {
39674011 delete params . headers . Authorization ;
39684012 delete params . headers [ 'token' ] ;
@@ -3971,8 +4015,23 @@ function submitRequest(params, callback) {
39714015 params . headers [ 'x-cos-security-token' ] && delete params . headers [ 'x-cos-security-token' ] ;
39724016 params . headers [ 'x-ci-security-token' ] && delete params . headers [ 'x-ci-security-token' ] ;
39734017 }
4018+ // 进入重试逻辑时 需判断是否需要切换cos备用域名
4019+ const switchHost = canSwitchHost . call ( self , {
4020+ requestUrl : err ?. url || '' ,
4021+ clientCalcSign : AuthData ?. SignFrom === 'client' ,
4022+ networkError,
4023+ } ) ;
4024+ params . SwitchHost = switchHost ;
39744025 next ( tryTimes + 1 ) ;
39754026 } 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+ }
39764035 callback ( err , data ) ;
39774036 }
39784037 } ) ;
@@ -4018,6 +4077,10 @@ function _submitRequest(params, callback) {
40184077 region : region ,
40194078 object : object ,
40204079 } ) ;
4080+ if ( params . SwitchHost ) {
4081+ // 更换请求的url
4082+ url = url . replace ( / m y q c l o u d .c o m / , 'tencentcos.cn' ) ;
4083+ }
40214084 if ( params . action ) {
40224085 url = url + '?' + params . action ;
40234086 }
@@ -4113,6 +4176,8 @@ function _submitRequest(params, callback) {
41134176 retResponse && retResponse . statusCode && ( attrs . statusCode = retResponse . statusCode ) ;
41144177 retResponse && retResponse . headers && ( attrs . headers = retResponse . headers ) ;
41154178 if ( err ) {
4179+ opt . url && ( attrs . url = opt . url ) ;
4180+ opt . method && ( attrs . method = opt . method ) ;
41164181 err = util . extend ( err || { } , attrs ) ;
41174182 callback ( err , null ) ;
41184183 } else {
0 commit comments