@@ -332,6 +332,9 @@ type ObjectPutHeaderOptions struct {
332332type ObjectPutOptions struct {
333333 * ACLHeaderOptions `header:",omitempty" url:"-" xml:"-"`
334334 * ObjectPutHeaderOptions `header:",omitempty" url:"-" xml:"-"`
335+
336+ // PutFromFile 使用
337+ innerSwitchURL * url.URL `header:"-" url:"-" xml:"-"`
335338}
336339
337340// Put Object请求可以将一个文件(Oject)上传至指定Bucket。
@@ -358,27 +361,58 @@ func (s *ObjectService) Put(ctx context.Context, name string, r io.Reader, uopt
358361 opt .ContentLength = totalBytes
359362 }
360363 }
361- reader := TeeReader (r , nil , totalBytes , nil )
362- if s .client .Conf .EnableCRC {
363- reader .writer = crc64 .New (crc64 .MakeTable (crc64 .ECMA ))
364- }
365- if opt != nil && opt .Listener != nil {
366- reader .listener = opt .Listener
367- }
368- sendOpt := sendOptions {
369- baseURL : s .client .BaseURL .BucketURL ,
370- uri : "/" + encodeURIComponent (name ),
371- method : http .MethodPut ,
372- body : reader ,
373- optHeader : opt ,
364+ // 如果是io.Seeker,则重试
365+ count := 1
366+ var position int64
367+ if seeker , ok := r .(io.Seeker ); ok {
368+ // 记录原始位置
369+ position , err = seeker .Seek (0 , io .SeekCurrent )
370+ if err == nil && s .client .Conf .RetryOpt .Count > 0 {
371+ count = s .client .Conf .RetryOpt .Count
372+ }
373+ }
374+ var resp * Response
375+ var retrieable bool
376+ sUrl := s .client .BaseURL .BucketURL
377+ if opt .innerSwitchURL != nil {
378+ sUrl = opt .innerSwitchURL
379+ }
380+ for nr := 0 ; nr < count ; nr ++ {
381+ reader := TeeReader (r , nil , totalBytes , nil )
382+ if s .client .Conf .EnableCRC {
383+ reader .writer = crc64 .New (crc64 .MakeTable (crc64 .ECMA ))
384+ }
385+ if opt != nil && opt .Listener != nil {
386+ reader .listener = opt .Listener
387+ }
388+ sendOpt := sendOptions {
389+ baseURL : sUrl ,
390+ uri : "/" + encodeURIComponent (name ),
391+ method : http .MethodPut ,
392+ body : reader ,
393+ optHeader : opt ,
394+ }
395+ resp , err = s .client .send (ctx , & sendOpt )
396+ sUrl , retrieable = s .client .CheckRetrieable (sUrl , resp , err )
397+ if retrieable && nr + 1 < count {
398+ if seeker , ok := r .(io.Seeker ); ok {
399+ _ , e := seeker .Seek (position , io .SeekStart )
400+ if e != nil {
401+ break
402+ }
403+ continue
404+ }
405+ }
406+ break
374407 }
375- resp , err := s .client .send (ctx , & sendOpt )
376-
377408 return resp , err
378409}
379410
380411// PutFromFile put object from local file
381412func (s * ObjectService ) PutFromFile (ctx context.Context , name string , filePath string , opt * ObjectPutOptions ) (resp * Response , err error ) {
413+ if opt == nil {
414+ opt = & ObjectPutOptions {}
415+ }
382416 nr := 0
383417 for nr < 3 {
384418 fd , e := os .Open (filePath )
@@ -390,6 +424,12 @@ func (s *ObjectService) PutFromFile(ctx context.Context, name string, filePath s
390424 if err != nil {
391425 nr ++
392426 fd .Close ()
427+ if s .client .Conf .RetryOpt .AutoSwitchHost {
428+ // 收不到报文 或者 不存在RequestId
429+ if resp == nil || resp .Header .Get ("X-Cos-Request-Id" ) == "" {
430+ opt .innerSwitchURL = toSwitchHost (s .client .BaseURL .BucketURL )
431+ }
432+ }
393433 continue
394434 }
395435 fd .Close ()
@@ -900,6 +940,12 @@ func worker(ctx context.Context, s *ObjectService, jobs <-chan *Jobs, results ch
900940 results <- & res
901941 break
902942 }
943+ if s .client .Conf .RetryOpt .AutoSwitchHost {
944+ // 收不到报文 或者 不存在RequestId
945+ if resp == nil || resp .Header .Get ("X-Cos-Request-Id" ) == "" {
946+ j .Opt .innerSwitchURL = toSwitchHost (s .client .BaseURL .BucketURL )
947+ }
948+ }
903949 time .Sleep (time .Millisecond )
904950 continue
905951 }
@@ -1128,6 +1174,7 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string
11281174 opt0 = & ObjectPutOptions {
11291175 opt .OptIni .ACLHeaderOptions ,
11301176 opt .OptIni .ObjectPutHeaderOptions ,
1177+ nil ,
11311178 }
11321179 }
11331180 rsp , err := s .PutFromFile (ctx , name , filepath , opt0 )
0 commit comments