Request management
Request management
Golang offers a context library that enables developers to actively control request behaviors. Starting from version 0.9.228, the Go SDK has introduced APIs with context parameters, allowing fine control of BOS requests. This update primarily supports request control through context parameters for APIs that may involve lengthy processing.
This article mainly introduces how to use these APIs. The APIs that support request control through context include:
- List buckets/list objects
- Upload objects
- Copy objects
- Download objects
- Append upload
- Fetch and upload
- Multipart upload/multipart copy
Object upload with context parameter
context.WithCancel returns a context object and its corresponding cancel method. It is up to the caller to decide when to execute the cancel method. The sample code is as follows:
1func PutObjectWithContext(bosClient *bos.Client, ctx context.Context, wg *sync.WaitGroup) {
2 bucketName := "bucket-test"
3 objectName := "prefix/object1"
4 fileName := "/path/to/localfile"
5 bodyStream, err := bce.NewBodyFromFile(fileName)
6 etag, err := bosClient.PutObjectFromFileWithContext(ctx, bucketName, objectName, fileName, &api.PutObjectArgs{})
7 if err == nil {
8 fmt.Printf("put object with context success: %s\n", etag)
9 } else {
10 fmt.Printf("put object with context failed: %s\n", err.Error())
11 }
12 wg.Done()
13}
14func main() {
15 AK, SK := "Your Access Key", "Your Secret Key"
16 ENDPOINT := "bj.bcebos.com"
17 bosClient, _ := bos.NewClient(AK, SK, ENDPOINT)
18
19 // Construct the context object and its cancel method
20 ctx, cancel := context.WithCancel(context.Background())
21 var wg sync.WaitGroup
22 wg.Add(1)
23 // Start a goroutine to upload the object
24 go PutObjectWithContext(bosClient, ctx)
25
26 // Call the cancel method after waiting for 3 seconds to cancel the object upload request
27 time.Sleep(3 * time.Second)
28 cancel()
29 wg.Wait()
30}
The context also provides the WithTimeout and WithDeadline methods to set the control behavior of the request. The sample code is as follows:
1// import "github.com/baidubce/bce-sdk-go/bce"
2ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
3//ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Millisecond))
4defer cancel()
5 // Upload from local file
6etag, err := bosClient.PutObjectFromFileWithContext(ctx, bucketName, objectName, fileName, nil)
7 // Upload from string
8str := "test put object"
9etag, err := bosClient.PutObjectFromStringWithContext(ctx, bucketName, objectName, str, nil)
10 // Upload from byte array
11byteArr := []byte("test put object")
12etag, err := bosClient.PutObjectFromBytesWithContext(ctx, bucketName, objectName, byteArr, nil)
13 // Upload from data stream
14bodyStream, err := bce.NewBodyFromFile(fileName)
15etag, err := bosClient.PutObjectWithContext(ctx, bucketName, objectName, bodyStream, nil)
Copy object with context parameter
Example code is as follows:
1// 1. Use the context.WithCancel method to control the request behavior
2ctx, cancel := context.WithCancel(context.Background())
3go bosClient.CopyObjectWithContext(ctx, bucketName, objectName, srcBucketName, srcObjectName, nil)
4time.Sleep(3 * time.Second)
5cancel()
6 // 2. Use context.WithTimeout and context.WithDeadline to control the request behavior
7ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
8//ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Millisecond))
9defer cancel()
10res, err := bosClient.CopyObjectWithContext(ctx, bucketName, objectName, srcBucketName, srcObjectName, nil)
11fmt.Println("ETag:", res.ETag, "LastModified:", res.LastModified)
Download object with context parameter
Example code is as follows:
1// 1. Use the context.WithCancel method to control the request behavior
2ctx, cancel := context.WithCancel(context.Background())
3 // Directly retrieve an object by providing the Bucket and Object
4res, err := bosClient.GetObjectWithContext(ctx, bucketName, objectName, nil)
5 // Retrieve ObjectMeta
6meta := res.ObjectMeta
7 // Retrieve the read stream (io.ReadCloser) of the Object
8stream := res.Body
9 // Ensure to disable the Object read stream
10defer stream.Close()
11 // Call the Read method of the stream object to process the Object
12...
13time.Sleep(3 * time.Second)
14cancel()
15 // 2. Use context.WithTimeout and context.WithDeadline to control the request behavior
16ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
17//ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Millisecond))
18defer cancel()
19res, err := bosClient.GetObjectWithContext(ctx, bucketName, objectName, nil)
20 // Retrieve the read stream (io.ReadCloser) of the Object
21stream := res.Body
22 // Ensure to disable the Object read stream
23defer stream.Close()
24 // Call the Read method of the stream object to process the Object
25...
Append object with context parameter
Example code is as follows:
1// import "github.com/baidubce/bce-sdk-go/services/bos/api"
2args := new(api.AppendObjectArgs)
3 // 1. Use the context.WithCancel method to control the request behavior
4ctx, cancel := context.WithCancel(context.Background())
5go bosClient.AppendObjectWithContext(ctx, bucketName, objectName, bodyStream, args)
6time.Sleep(3 * time.Second)
7cancel()
8 // 2. Use context.WithTimeout and context.WithDeadline to control the request behavior
9ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
10//ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Millisecond))
11defer cancel()
12res, err := bosClient.AppendObjectWithContext(ctx, bucketName, objectName, bodyStream, args)
13 fmt.Println(res.ETag) // Print ETag
14 fmt.Println(res.ContentMD5) // Print ContentMD5
15 fmt.Println(res.NextAppendOffset) // Print NextAppendOffset
Fetch and upload with context parameter
Example code is as follows:
1// import "github.com/baidubce/bce-sdk-go/services/bos/api"
2args := new(api.FetchObjectArgs)
3 // 1. Use the context.WithCancel method to control the request behavior
4ctx, cancel := context.WithCancel(context.Background())
5args.FetchMode = api.FETCH_MODE_SYNC
6go bosClient.FetchObject(bucketName, objectName, url, args)
7time.Sleep(3 * time.Second)
8cancel()
9 // 2. Use context.WithTimeout and context.WithDeadline to control the request behavior
10ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
11//ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Millisecond))
12defer cancel()
13res, err := bosClient.FetchObject(bucketName, objectName, url, args)
14 fmt.Printf("res: %v", res) // Print the fetch result
Multipart upload with context parameter
Multipart upload includes: initializing multipart upload, uploading parts, and completing multipart upload. Among them, initializing multipart upload and completing multipart upload are generally not used to control request behaviors through context. For the calling methods, please refer to the introduction of initializing multipart upload and completing multipart upload in Go SDK File Management - Multipart Upload. Here we introduce the request of controlling part upload through context. The sample code is as follows:
1// import "github.com/baidubce/bce-sdk-go/bce"
2// import "github.com/baidubce/bce-sdk-go/services/bos"
3// import "github.com/baidubce/bce-sdk-go/services/bos/api"
4file, _ := os.Open("/path/to/file.zip")
5 // The part size is aligned with MULTIPART_ALIGN = 1 MB
6partSize := (bosClient.MultipartSize +
7 bos.MULTIPART_ALIGN - 1) / bos.MULTIPART_ALIGN * bos.MULTIPART_ALIGN
8 // Get the file size and calculate the number of parts. The maximum number of parts is MAX_PART_NUMBER = 10,000
9fileInfo, _ := file.Stat()
10fileSize := fileInfo.Size()
11partNum := (fileSize + partSize - 1) / partSize
12 if partNum > bos.MAX_PART_NUMBER { // If the maximum number of parts is exceeded, the part size needs to be adjusted
13 partSize = (fileSize + bos.MAX_PART_NUMBER + 1) / bos.MAX_PART_NUMBER
14 partSize = (partSize + bos.MULTIPART_ALIGN - 1) / bos.MULTIPART_ALIGN * bos.MULTIPART_ALIGN
15 partNum = (fileSize + partSize - 1) / partSize
16}
17 // Create a list to save the ETag and PartNumber information after each part is uploaded
18partEtags := make([]api.UploadInfoType, 0)
19 // Upload parts one by one
20for i := int64(1); i <= partNum; i++ {
21 // Calculate the offset and the upload size of this time
22 uploadSize := partSize
23 offset := partSize * (i - 1)
24 left := fileSize - offset
25 if left < partSize {
26 uploadSize = left
27 }
28 // Create a file stream with specified offset and size
29 partBody, _ := bce.NewBodyFromSectionFile(file, offset, uploadSize)
30 // Use context.WithTimeout and context.WithDeadline to control the request behavior
31 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
32 //ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Millisecond))
33 defer cancel()
34 // Upload the current part
35 etag, err := bosClient.UploadPartWithContext(ctx, bucketName, objectKey, uploadId, int(i), partBody, nil)
36 // Save the serial number and ETag returned after the current part is uploaded successfully
37 partEtags = append(partEtags, api.UploadInfoType{int(i), etag})
38}
Multipart copy with context parameter
The basic process of multipart copy is similar to that of multipart upload, including three steps: initializing multipart copy, copying parts, and completing multipart copy. The first and third steps are the same as those of multipart upload. The second step of part copying is completed using the UploadPartCopy method, and the multipart copy method with context parameter is UploadPartCopyWithContext.
Initialize multipart upload
The supported fields for the multipart copy initialization parameter InitiateMultipartUploadArgs are as follows:
| Name | Description | Default value |
|---|---|---|
| CacheControl | Specify the caching behavior of the web page when the object is downloaded | None |
| ContentDisposition | Indicate how the MIME user agent displays the attached file, whether to open or download it, and the file name | None |
| Expires | Cache expiration time | None |
| StorageClass | Specify the storage class of the target object for copying | Standard storage |
| ObjectTagging | Specify the tag of the target object for copying | None |
The value of the initialization parameters mentioned above can be set based on the meta-information of the source object being copied, or customized according to specific usage requirements.
The sample code for initializing multipart copy is as follows:
1// import "github.com/baidubce/bce-sdk-go/bce"
2// import "github.com/baidubce/bce-sdk-go/services/bos"
3// import "github.com/baidubce/bce-sdk-go/services/bos/api"
4 // Get the meta information of the source object for copying
5srcObjectMeta, err := srcClient.GetObjectMeta(srcBucketName, srcObjectName)
6 // Set the meta information of the source object for copying to the initialization parameters of the target object for copying, and set specific parameters as needed
7initArgs := api.InitiateMultipartUploadArgs{
8 CacheControl: srcObjectMeta.CacheControl,
9 ContentDisposition: srcObjectMeta.ContentDisposition,
10 Expires: srcObjectMeta.Expires,
11 StorageClass: srcObjectMeta.StorageClass,
12}
13initRes, err := api.InitiateMultipartUpload(c, destBucketName, destObjectName, srcObjectMeta.ContentType, &initArgs, c.BosContext)
Multipart Copy
After completing the initialization of multipart copy, execute the multipart copy. The multipart copy can be controlled through context. The sample code is as follows:
1// import "github.com/baidubce/bce-sdk-go/bce"
2// import "github.com/baidubce/bce-sdk-go/services/bos"
3// import "github.com/baidubce/bce-sdk-go/services/bos/api"
4size := srcObjectMeta.ContentLength
5 // The part size is aligned with MULTIPART_ALIGN = 1 MB
6partSize := (bosClient.MultipartSize + bos.MULTIPART_ALIGN - 1) / bos.MULTIPART_ALIGN * bos.MULTIPART_ALIGN
7 // Calculate the number of parts. The maximum number of parts is MAX_PART_NUMBER = 10,000
8dstObjectSize := srcObjectMeta.ContentLength
9partNum := (dstObjectSize + partSize - 1) / partSize
10 if partNum > bos.MAX_PART_NUMBER { // If the maximum number of parts is exceeded, the part size needs to be adjusted
11 partSize = (dstObjectSize + bos.MAX_PART_NUMBER + 1) / bos.MAX_PART_NUMBER
12 partSize = (partSize + bos.MULTIPART_ALIGN - 1) / bos.MULTIPART_ALIGN * bos.MULTIPART_ALIGN
13 partNum = (dstObjectSize + partSize - 1) / partSize
14}
15 // Create a list to save the ETag and PartNumber information after each part is uploaded
16partEtags := make([]api.UploadInfoType, 0)
17 // Upload parts one by one
18for i := 1; i <= partNum; i++ {
19 // Calculate the offset and the upload size of this time
20 uploadSize := partSize
21 offset := partSize * (i - 1)
22 left := fileSize - offset
23 if left < partSize {
24 uploadSize = left
25 }
26 partCopyArgs := api.UploadPartCopyArgs{
27 SourceRange: fmt.Sprintf("bytes=%d-%d", (i-1)*partSize, (i-1)*partSize+uploadSize-1),
28 IfMatch: srcMeta.ETag,
29 }
30 source := fmt.Sprintf("/%s/%s", srcBucketName, srcObjectName)
31 copyObjectResult, err := bosClient.UploadPartCopyWithContext(ctx, destBucketName, destObjectName, source, uploadId, i, args)
32 // Save the serial number and ETag returned after the current part is uploaded successfully
33 partEtags = append(partEtags, api.UploadInfoType{i, copyObjectResult.ETag})
34}
Complete multipart upload
After all parts are copied successfully, finally execute the step of completing the multipart copy. The sample code is as follows:
1// import "github.com/baidubce/bce-sdk-go/services/bos/api"
2completeArgs := api.CompleteMultipartUploadArgs{Parts: partEtags}
3res, err := bosClient.CompleteMultipartUploadFromStruct(destBucketName, destObjectName, initRes.UploadId, &completeArgs)
4 // Output the content of the result object
5fmt.Println(res.Location)
6fmt.Println(res.Bucket)
7fmt.Println(res.Key)
8fmt.Println(res.ETag)
