By default, the access control list (ACL) of an object in an Object Storage Service (OSS) bucket is set to private, meaning only the object owner has permission to access it. However, the owner can generate a presigned URL to grant temporary access for others to upload objects within a specified time frame. This feature enables scenarios such as allowing partners to upload contracts or users to submit profile images.
Notes
In this topic, the public endpoint of the China (Hangzhou) region is used. To access OSS from other Alibaba Cloud services in the same region, use an internal endpoint. For details about supported regions and endpoints, see Regions and endpoints.
You do not need specific permissions to generate a presigned URL. However, to allow others to use the presigned URL for uploading an object, you must have the
oss:PutObject
permission. For more information, see Authorize a RAM user to access multiple directories in a bucket.Presigned URLs do not support FormData uploads. For FormData uploads, use form uploads instead.
Workflow
The following figure shows the process of uploading an object to OSS by using a presigned URL.
Use a presigned URL to upload an object
The bucket owner generates a presigned URLthat allows PUT requests.
NoteA presigned URL generated by using the OSS SDK has a maximum validity period of 7 days. If you generate a presigned URL by using a Security Token Service (STS) token, it can be valid for up to 12 hours (43,200 seconds).
Java
For information about how to use OSS SDK for Java to generate a presigned URL, see OSS SDK for Java.
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import java.net.URL; import java.util.*; import java.util.Date; public class GetSignUrl { public static void main(String[] args) throws Throwable { // The public endpoint of China (Hangzhou) is used as an example. For other regions, replace the value with your actual information. String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // Retrieve access credentials from environment variables. Before running this code, ensure that environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET are set. EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // Specify the bucket name, for example, "examplebucket". String bucketName = "examplebucket"; // Specify the full path of the object, for example, "exampleobject.txt". The object path should not include the bucket name. String objectName = "exampleobject.txt"; // Specify the region where the bucket is located. For example, if the bucket is in China (Hangzhou), set the region to cn-hangzhou. String region = "cn-hangzhou"; // Create an OSSClient instance. ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); URL signedUrl = null; try { // Specify the validity period for the generated presigned URL in milliseconds. In this example, the expiration time is set to 1 hour. Date expiration = new Date(new Date().getTime() + 3600 * 1000L); // Generate a presigned URL. GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT); // Specify the expiration time of the presigned URL. request.setExpiration(expiration); // Generate a presigned URL that allows the HTTP PUT method. signedUrl = ossClient.generatePresignedUrl(request); // Display the presigned URL. System.out.println("signed url for putObject: " + signedUrl); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } } }
Go
For information about how to use OSS SDK for Go to generate a presigned URL, see OSS SDK for Go.
package main import ( "context" "flag" "log" "time" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" ) // Define global variables. var ( region string // The region of the bucket. bucketName string // The name of the bucket. objectName string // The name of the object. ) // Define the init function to initialize the command-line parameters. func init() { flag.StringVar(®ion, "region", "", "The region in which the bucket is located.") flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.") flag.StringVar(&objectName, "object", "", "The name of the object.") } func main() { // Parse the command-line parameters. flag.Parse() // Check whether the bucket name is empty. if len(bucketName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, bucket name required") } // Check whether the region is empty. if len(region) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, region required") } // Check whether the object name is empty. if len(objectName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, object name required") } // Load the default configuration and specify the credential provider and region. cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region) // Create an OSS client instance. client := oss.NewClient(cfg) // Generate a presigned URL with the PutObject method. result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("failed to put object presign %v", err) } log.Printf("request method:%v\n", result.Method) log.Printf("request expiration:%v\n", result.Expiration) log.Printf("request url:%v\n", result.URL) if len(result.SignedHeaders) > 0 { //If the returned result contains signature headers, ensure you include these headers when making a PUT request with the presigned URL. log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
Python
For information about how to use OSS SDK for Python to generate a presigned URL, see OSS SDK for Python.
import argparse import requests import alibabacloud_oss_v2 as oss from datetime import datetime, timedelta # Create a command line parameter parser and describe the purpose of the script. The example describes how to generate a presigned URL that allows HTTP PUT requests. parser = argparse.ArgumentParser(description="presign put object sample") # Specify the command line parameters, including the required region, bucket name, endpoint, and object name. parser.add_argument('--region', help='The region in which the bucket is located.', required=True) parser.add_argument('--bucket', help='The name of the bucket.', required=True) parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS') parser.add_argument('--key', help='The name of the object.', required=True) def main(): # Parse the command line parameters to obtain the values specified by the user. args = parser.parse_args() # Obtain access credentials from environment variables for authentication. credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() # Use the default configurations of the SDK to create a configuration object and specify the credential provider. cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider # Specify the region attribute of the configuration object based on the command line parameters specified by the user. cfg.region = args.region # If a custom endpoint is provided, modify the endpoint parameter in the configuration object. if args.endpoint is not None: cfg.endpoint = args.endpoint # Use the preceding configurations to initialize the OSSClient instance and allow the instance to interact with OSS. client = oss.Client(cfg) # Send the request to initiate a PUT request and generate a presigned URL for the specified object. pre_result = client.presign(oss.PutObjectRequest( bucket=args.bucket, # The name of the bucket. key=args.key, # The name of the object. ),expires=timedelta(seconds=3600)) # Specify the validity period of the request. In this example, the validity period is set to 3,600 seconds. # Display the method, expiration time, and presigned URL specified in the request to check the validity of the presigned URL. print(f'method: {pre_result.method},' f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},' f' url: {pre_result.url}' ) # Display the signed headers in the request, which are included in the HTTP header when the request is sent. for key, value in pre_result.signed_headers.items(): print(f'signed headers key: {key}, signed headers value: {value}') # Call the main function to start the processing logic when the script is directly run. if __name__ == "__main__": main() # Specify the entry points in the functions of the script. The control program flow starts here.
Node.js
The following example generates a presigned URL for regular uploads. For information about how to use OSS SDK for Node.js to generate a presigned URL with image processing parameters or a version ID, see OSS SDK for Node.js.
const OSS = require("ali-oss"); // Specify a function used to generate a presigned URL. async function generateSignatureUrl(fileName) { // Obtain the presigned URL. const client = await new OSS({ accessKeyId: 'yourAccessKeyId', accessKeySecret: 'yourAccessKeySecret', bucket: 'examplebucket', region: 'oss-cn-hangzhou', authorizationV4: true }); return await client.signatureUrlV4('PUT', 3600, { headers: {} // Specify the request headers based on the actual request headers. }, fileName); } // Call the function and pass in the object name. generateSignatureUrl('yourFileName').then(url => { console.log('Generated Signature URL:', url); }).catch(err => { console.error('Error generating signature URL:', err); });
PHP
The following example generates a presigned URL for regular uploads. For information about how to use OSS SDK for PHP to generate a presigned URL with a version ID, see OSS SDK for PHP.
<?php if (is_file(__DIR__ . '/../autoload.php')) { require_once __DIR__ . '/../autoload.php'; } if (is_file(__DIR__ . '/../vendor/autoload.php')) { require_once __DIR__ . '/../vendor/autoload.php'; } use OSS\OssClient; use OSS\Core\OssException; use OSS\Http\RequestCore; use OSS\Http\ResponseCore; use OSS\Credentials\EnvironmentVariableCredentialsProvider; // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. $provider = new EnvironmentVariableCredentialsProvider(); // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. $endpoint = "yourEndpoint"; // Specify the name of the bucket. $bucket= "examplebucket"; // Specify the full path of the object. Do not include the bucket name in the full path of the object. $object = "exampleobject.txt"; // Set the validity period of the presigned URL to 600 seconds. Maximum value: 32400. $timeout = 600; try { $config = array( "provider" => $provider, "endpoint" => $endpoint, 'signatureVersion'=>OssClient::OSS_SIGNATURE_VERSION_V4, "region"=> "cn-hangzhou" ); $ossClient = new OssClient($config); // Generate the presigned URL. $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT"); print_r($signedUrl); } catch (OssException $e) { printf(__FUNCTION__ . ": FAILED\n"); printf($e->getMessage() . "\n"); return; }
Android
For information about how to use OSS SDK for Android to generate a presigned URL, see Access authorization.
// Specify the name of the bucket. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the source object. Do not include the bucket name in the full path. Example: exampleobject.txt. String objectKey = "exampleobject.txt"; // Specify the contentType header. String contentType = "application/octet-stream"; String url = null; try { // Generate a presigned URL to upload the object. GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey); // Set the validity period of the presigned URL to 30 minutes. request.setExpiration(30*60); request.setContentType(contentType); request.setMethod(HttpMethod.PUT); url = oss.presignConstrainedObjectURL(request); Log.d("url", url); } catch (ClientException e) { e.printStackTrace(); }
C++
For information about how to use OSS SDK for C++ to generate a presigned URL, see Authorize access.
#include <alibabacloud/oss/OssClient.h> using namespace AlibabaCloud::OSS; int main(void) { /* Initialize information about the account that is used to access OSS. */ /* Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. */ std::string Endpoint = "yourEndpoint"; /* Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. * / std::string Region = "yourRegion"; /* Specify the name of the bucket. Example: examplebucket. */ std::string BucketName = "examplebucket"; /* Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. */ std::string PutobjectUrlName = "exampledir/exampleobject.txt"; /* Initialize resources, such as network resources. */ InitializeSdk(); ClientConfiguration conf; conf.signatureVersion = SignatureVersionType::V4; /* Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. */ auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>(); OssClient client(Endpoint, credentialsProvider, conf); client.SetRegion(Region); /* Specify the validity period of the pre-signed URL. The maximum validity period is 32,400. Unit: seconds. */ std::time_t t = std::time(nullptr) + 1200; /* Generate a pre-signed URL. */ auto genOutcome = client.GeneratePresignedUrl(BucketName, PutobjectUrlName, t, Http::Put); if (genOutcome.isSuccess()) { std::cout << "GeneratePresignedUrl success, Gen url:" << genOutcome.result().c_str() << std::endl; } else { /* Handle exceptions. */ std::cout << "GeneratePresignedUrl fail" << ",code:" << genOutcome.error().Code() << ",message:" << genOutcome.error().Message() << ",requestId:" << genOutcome.error().RequestId() << std::endl; return -1; } /* Release resources, such as network resources. */ ShutdownSdk(); return 0; }
iOS
For information about how to use OSS SDK for iOS to generate a presigned URL, see Authorize access.
// Specify the name of the bucket. NSString *bucketName = @"examplebucket"; // Specify the name of the object. NSString *objectKey = @"exampleobject.txt"; NSURL *file = [NSURL fileURLWithPath:@"<filePath>"]; NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey]; __block NSString *urlString; // Generate a presigned URL with a validity period for uploading the object. In this example, the validity period of the URL is 30 minutes. OSSTask *task = [client presignConstrainURLWithBucketName:bucketName withObjectKey:objectKey httpMethod:@"PUT" withExpirationInterval:30 * 60 withParameters:@{} contentType:contentType contentMd5:nil]; [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) { if (task.error) { NSLog(@"presign error: %@", task.error); } else { urlString = task.result; NSLog(@"url: %@", urlString); } return nil; }];
.NET
For information about how to use OSS SDK for .NET to generate a presigned URL, see Use a presigned URL to upload an object.
using Aliyun.OSS; using Aliyun.OSS.Common; // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. var endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID"); var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET"); // Specify the name of the bucket. Example: examplebucket. var bucketName = "examplebucket"; // Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. var objectName = "exampledir/exampleobject.txt"; var objectContent = "More than just cloud."; // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. const string region = "cn-hangzhou"; // Create a ClientConfiguration instance and modify the default parameter settings based on your requirements. var conf = new ClientConfiguration(); // Specify the V4 signature algorithm. conf.SignatureVersion = SignatureVersion.V4; // Create an OSSClient instance. var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf); conf.SetRegion(region); try { // Generate a presigned URL. var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put) { // Set the validity period of the presigned URL. Default value: 3600. Unit: seconds. Expiration = DateTime.Now.AddHours(1), }; var signedUrl = client.GeneratePresignedUri(generatePresignedUriRequest); } catch (OssException ex) { Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}", ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId); } catch (Exception ex) { Console.WriteLine("Failed with error info: {0}", ex.Message); }
C
For information about how to use OSS SDK for C to generate a presigned URL, see Authorize access.
#include "oss_api.h" #include "aos_http_io.h" /* Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. */ const char *endpoint = "yourEndpoint"; /* Specify the name of the bucket. Example: examplebucket. */ const char *bucket_name = "examplebucket"; /* Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. */ const char *object_name = "exampledir/exampleobject.txt"; /* Specify the full path of the local file. */ const char *local_filename = "yourLocalFilename"; void init_options(oss_request_options_t *options) { options->config = oss_config_create(options->pool); /* Use a char* string to initialize aos_string_t. */ aos_str_set(&options->config->endpoint, endpoint); /* Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. */ aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID")); aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET")); /* Specify whether to use CNAME. The value 0 indicates that CNAME is not used. */ options->config->is_cname = 0; /* Configure network parameters, such as the timeout period. */ options->ctl = aos_http_controller_create(options->pool, 0); } int main(int argc, char *argv[]) { /* Call the aos_http_io_initialize method in main() to initialize global resources, such as network and memory resources. */ if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { exit(1); } /* Create a memory pool to manage memory. aos_pool_t is equivalent to apr_pool_t. The code that is used to create a memory pool is included in the APR library. */ aos_pool_t *pool; /* Create a memory pool. The value of the second parameter is NULL. This value specifies that the pool does not inherit other memory pools. */ aos_pool_create(&pool, NULL); /* Create and initialize options. This parameter includes global configuration information, such as endpoint, access_key_id, access_key_secret, is_cname, and curl. */ oss_request_options_t *oss_client_options; /* Allocate memory resources in the memory pool to the options. */ oss_client_options = oss_request_options_create(pool); /* Initialize oss_client_options. */ init_options(oss_client_options); /* Initialize the parameters. */ aos_string_t bucket; aos_string_t object; aos_string_t file; aos_http_request_t *req; apr_time_t now; char *url_str; aos_string_t url; int64_t expire_time; int one_hour = 3600; aos_str_set(&bucket, bucket_name); aos_str_set(&object, object_name); aos_str_set(&file, local_filename); expire_time = now / 1000000 + one_hour; req = aos_http_request_create(pool); req->method = HTTP_PUT; now = apr_time_now(); /* Specify the validity period. Unit: microseconds * / expire_time = now / 1000000 + one_hour; /* Generate a presigned URL. */ url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req); aos_str_set(&url, url_str); printf("The signed URL used to upload the object: %s\n", url_str); /* Release the memory pool. This operation releases memory resources allocated for the request. */ aos_pool_destroy(pool); /* Release the allocated global resources. */ aos_http_io_deinitialize(); return 0; }
Others upload objects by using the presigned URL to send a PUT request.
ImportantA presigned URL can be used multiple times before it expires. However, if you upload the same object multiple times, each new upload will overwrite the previous one. Once the URL expires, the owner needs to generate a new presigned URL (as shown in Step 1) for others to have prolonged access.
Use presigned URLs to upload an object in parts
If you need to upload large objects but find it difficult or impossible to integrate an OSS SDK into your client, consider multipart uploads by using presigned URLs. In this approach, the server initiates the upload process, and each part is assigned a presigned URL for your client or third-party service to upload individually. Once all parts are successfully uploaded, the server combines them into a complete object.
Uploading an object in parts by using presigned URLs is more complex than by using an OSS SDK. When you upload an object in parts by using presigned URLs, ensure that your client uploads a part corresponding to the part number specified in the presigned URL. A missing part or part mismatch will cause a failure in combining the parts. If your client supports OSS SDK integration, we recommend that you use client direct uploads based on STS tokens for greater simplicity and stability.
The client sends a multipart upload request.
The client submits a multipart upload request including the object name, object size, and part size. The part size is limited to a maximum of 5 GB, with a recommended value of 5 MB.
The following code is an example of a multipart upload sent by the client. When using the example, remember to replace
https://yourserver.com/init-upload
with your actual initialization endpoint on your server.curl -X POST https://yourserver.com/init-upload \ -H "Content-Type: application/json" \ -d '{ "fileName": "exampleobject.jpg", "fileSize": 104857600, "partSize": 5242880 }'
The server initiates the multipart upload and generates presigned URLs.
Calls the InitiateMultipartUpload to initiate the upload and get the the upload ID.
Calculates the number of parts based on the object size and part size.
Generates a presigned URL for each part.
Returns a list of presigned URLs in JSON form.
NoteThe server records the upload ID, which uniquely identifies the multipart upload and is used to verify and combine parts. You can store the upload ID by using cache, databases, or other methods.
The client uploads the object in parts.
The client sends PUT requests to upload individual parts by using the presigned URLs returned by the server. Each part is upload in the same way as uploading an object with a presigned URL. After all the parts are uploaded, the client notifies the server of combining the parts.
NoteMultipart uploads via presigned URLs support concurrent processing, but it is critical to ensure that each URL is used exclusively for its designated part. For example, the part number N in the URL must be used to upload the Nth part of the file, and no reuse or skipping of part numbers is allowed.
The following sample command uploads the first part (/path/to/local/file is the path of the local file):
curl -X PUT -T /path/to/local/file "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.jpg?partNumber=1\u0026uploadId=BE2D0BC931BE4DE1B23F339AABFA49EE\u0026x-oss-credential=LTAI********************%2F20250520%2Fcn-hangzhou%2Foss%2Faliyun_v4_request\u0026x-oss-date=20250520T082728Z\u0026x-oss-expires=3600\u0026x-oss-signature=81f3d2e5eaa67c432291577ed20af3b3f60df05ab3cddedcdce168ef707f7ad0\u0026x-oss-signature-version=OSS4-HMAC-SHA256"
(Optional) The server verifies uploaded parts.
You can optionally configure the server to verify uploaded parts when it is notified of part upload completion.
Verify the integrity of uploaded parts.
Verify that each part is of the expected size.
NotePart verification requires the upload ID recorded earlier.
The server combines the parts and returns the upload result.
After part verification passes, the server calls the CompleteMultipartUpload operation to combine the parts into a whole object and returns the upload result to the client.
Configure headers to specify the upload policy
When generating a presigned URL, you can define an upload policy by specifying the Header parameter. For example, you can set headers such as x-oss-storage-class
(to define the storage class) and Content-Type
(to specify the object type).
If you include headers when generating the presigned URL, you must provide the same headers when uploading the object. If the headers do not match, OSS will return a 403 error due to signature verification failure.
For information about supported headers, see PutObject. You can also configure custom headers to manage object metadata. For more information, see Manage object metadata.
The object owner generates a presigned URL with the Header parameter.
Java
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.internal.OSSHeaders; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import com.aliyun.oss.model.StorageClass; import java.net.URL; import java.util.*; import java.util.Date; public class GetSignUrl { public static void main(String[] args) throws Throwable { // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // Specify the name of the bucket. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object. Example: exampleobject.txt. Do not include the bucket name in the full path of the object. String objectName = "exampleobject.txt"; // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. String region = "cn-hangzhou"; // Create an OSSClient instance. // Call the shutdown method to release resources when the OSSClient is no longer in use. ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); // Specify request headers. Map<String, String> headers = new HashMap<String, String>(); // Specify the storage class. headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString()); // Specify the content type. headers.put(OSSHeaders.CONTENT_TYPE, "text/plain; charset=utf8"); // Specify user metadata. Map<String, String> userMetadata = new HashMap<String, String>(); userMetadata.put("key1","value1"); userMetadata.put("key2","value2"); URL signedUrl = null; try { // Specify the validity period of the presigned URL. Unit: milliseconds. In this example, the validity period is set to 1 hour. Date expiration = new Date(new Date().getTime() + 3600 * 1000L); // Generate a presigned URL. GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT); // Specify the validity period of the presigned URL. request.setExpiration(expiration); // Add headers to the request. request.setHeaders(headers); // Specify user metadata. request.setUserMetadata(userMetadata); // Generate a presigned URL that allows HTTP PUT requests. signedUrl = ossClient.generatePresignedUrl(request); // Display the presigned URL. System.out.println("signed url for putObject: " + signedUrl); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } } }
Go
package main import ( "context" "flag" "log" "time" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" ) // 定义全局变量 var ( region string // 存储区域 bucketName string // 存储空间名称 objectName string // 对象名称 ) // init函数用于初始化命令行参数 func init() { flag.StringVar(®ion, "region", "", "The region in which the bucket is located.") flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.") flag.StringVar(&objectName, "object", "", "The name of the object.") } func main() { // 解析命令行参数 flag.Parse() // 检查bucket名称是否为空 if len(bucketName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, bucket name required") } // 检查region是否为空 if len(region) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, region required") } // 检查object名称是否为空 if len(objectName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, object name required") } // 加载默认配置并设置凭证提供者和区域 cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region) // 创建OSS客户端 client := oss.NewClient(cfg) // 生成PutObject的预签名URL result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), ContentType: oss.Ptr("text/plain;charset=utf8"), // 请确保在服务端生成该签名URL时设置的ContentType与在使用URL时设置的ContentType一致 StorageClass: oss.StorageClassStandard, // 请确保在服务端生成该签名URL时设置的StorageClass与在使用URL时设置的StorageClass一致 Metadata: map[string]string{"key1": "value1", "key2": "value2"}, // 请确保在服务端生成该签名URL时设置的Metadata与在使用URL时设置的Metadata一致 }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("failed to put object presign %v", err) } log.Printf("request method:%v\n", result.Method) log.Printf("request expiration:%v\n", result.Expiration) log.Printf("request url:%v\n", result.URL) if len(result.SignedHeaders) > 0 { //当返回结果包含签名头时,使用预签名URL发送Put请求时,需要设置相应的请求头 log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
Python
import argparse import requests import alibabacloud_oss_v2 as oss from datetime import datetime, timedelta # Create a command line parameter parser and describe the purpose of the script. The example describes how to generate a presigned URL that allows HTTP PUT requests. parser = argparse.ArgumentParser(description="presign put object sample") # Specify the command line parameters, including the required region, bucket name, endpoint, and object name. parser.add_argument('--region', help='The region in which the bucket is located.', required=True) parser.add_argument('--bucket', help='The name of the bucket.', required=True) parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS') parser.add_argument('--key', help='The name of the object.', required=True) def main(): # Parse the command line parameters to obtain the values specified by the user. args = parser.parse_args() # Obtain access credentials from environment variables for authentication. credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() # Use the default configurations of the SDK to create a configuration object and specify the credential provider. cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider # Specify the region attribute of the configuration object based on the command line parameters specified by the user. cfg.region = args.region # If a custom endpoint is provided, modify the endpoint parameter in the configuration object. if args.endpoint is not None: cfg.endpoint = args.endpoint # Use the preceding configurations to initialize the OSSClient instance and allow the instance to interact with OSS. client = oss.Client(cfg) # Send the request to initiate a PUT request and generate a presigned URL for the specified object. pre_result = client.presign(oss.PutObjectRequest( bucket=args.bucket, # The name of the bucket. key=args.key, # The name of the object. content_type='text/plain;charset=utf8', # Specify the type of the object. storage_class='Standard', # Specify the storage class of the object. metadata={ 'key1': 'value1', # Specify the metadata of the object. 'key2': 'value2' # Specify the metadata of the object. } ),expires=timedelta(seconds=3600)) # Specify the validity period of the request. In this example, the validity period is set to 3,600 seconds. # Display the method, expiration time, and presigned URL specified in the request to check the validity of the presigned URL. print(f'method: {pre_result.method},' f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},' f' url: {pre_result.url}' ) # Display the signed headers in the request, which are included in the HTTP header when the request is sent. for key, value in pre_result.signed_headers.items(): print(f'signed headers key: {key}, signed headers value: {value}') # Call the main function to start the processing logic when the script is directly run. if __name__ == "__main__": main() # Specify the entry points in the functions of the script. The control program flow starts here.
Others upload objects by using the presigned URL while providing the same headers.
curl
curl -X PUT \ -H "Content-Type: text/plain;charset=utf8" \ -H "x-oss-storage-class: Standard" \ -H "x-oss-meta-key1: value1" \ -H "x-oss-meta-key2: value2" \ -T "C:\\Users\\demo.txt" \ "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"
Java
import com.aliyun.oss.internal.OSSHeaders; import com.aliyun.oss.model.StorageClass; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import java.io.*; import java.net.URL; import java.util.*; public class SignUrlUpload { public static void main(String[] args) throws Throwable { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; // Replace with the signed URL. URL signedUrl = new URL(""); // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. String pathName = "C:\\Users\\demo.txt"; // Specify request headers. Make sure that the values of the request headers are the same as that of the request headers when the signed URL is generated. Map headers = new HashMap(); //Specify the storage class. headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString()); //Specify the content type. headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8"); // Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated. Map userMetadata = new HashMap(); userMetadata.put("key1","value1"); userMetadata.put("key2","value2"); try { HttpPut put = new HttpPut(signedUrl.toString()); System.out.println(put); HttpEntity entity = new FileEntity(new File(pathName)); put.setEntity(entity); // If you configure headers such as the user metadata and storage class when the presigned URL was generated, these headers must be sent to the server when the presigned URL is used to upload a file. If the headers that are sent to the server for the signature calculation are inconsistent with those specified when the presigned URL was generated, a signature error is reported. for(Map.Entry header: headers.entrySet()){ put.addHeader(header.getKey().toString(),header.getValue().toString()); } for(Map.Entry meta: userMetadata.entrySet()){ // If user metadata is specified, the SDK adds the "x-oss-meta-" prefix to the user metadata key. If you use other methods to upload a file, make sure that the "x-oss-meta-" prefix is also added to the user metadata key. put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString()); } httpClient = HttpClients.createDefault(); response = httpClient.execute(put); System.out.println("Status code of the upload: "+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("The object is uploaded by using the network library"); } System.out.println(response.toString()); } catch (Exception e){ e.printStackTrace(); } finally { response.close(); httpClient.close(); } } }
Go
package main import ( "bytes" "fmt" "io/ioutil" "net/http" "os" ) func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error { // Open the local file file, err := os.Open(filePath) if err != nil { return err } defer file.Close() // Read the object content fileBytes, err := ioutil.ReadAll(file) if err != nil { return err } // Create a request req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes)) if err != nil { return err } // Specify request headers for key, value := range headers { req.Header.Set(key, value) } // Specify user metadata for key, value := range metadata { req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value) } // Send the request client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() // Process the response fmt.Printf("Status code: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("The object is uploaded by using the network library") } else { fmt.Println("Upload failed") } body, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) return nil } func main() { // Replace with the signed URL. signedUrl := "" // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. filePath := "C:\\Users\\demo.txt" // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated. headers := map[string]string{ "Content-Type": "text/plain;charset=utf8", "x-oss-storage-class": "Standard", } // Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated. metadata := map[string]string{ "key1": "value1", "key2": "value2", }, headers, metadata) if err != nil { fmt.Printf("An error occurred: %v\n", err) } }
Python
import requests from requests.auth import HTTPBasicAuth import os def upload_file(signed_url, file_path, headers=None, metadata=None): """ Use a pre-signed URL to upload an object to OSS. :param signed_url: the presigned URL. :param file_path: the full path of the local file that you want to upload. :param headers: Optional. Specify the request headers. :param metadata: user metadata. This parameter is optional. :return: None """ if not headers: headers = {} if not metadata: metadata = {} # Add the x-oss-meta- prefix to the metadata key. for key, value in metadata.items(): headers[f'x-oss-meta-{key}'] = value try: with open(file_path, 'rb') as file: response = requests.put(signed_url, data=file, headers=headers) print(f"Status code: {response.status_code}") if response.status_code == 200: print("The object is uploaded by using the network library") else: print("Upload failed") print(response.text) except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": # Replace with the signed URL. signed_url = "" # Specify the full path of the local file. By default, if you do not specify the full path of a local file, the local file is uploaded from the directory in which the script is stored. file_path = "C:\\Users\\demo.txt" # Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated. headers = { "Content-Type": "text/plain;charset=utf8", "x-oss-storage-class": "Standard" } # Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated. metadata = { "key1": "value1", "key2": "value2" } upload_file(signed_url, file_path, headers, metadata)
Node.js
const fs = require('fs'); const axios = require('axios'); async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) { try { // Update the request headers and specify the metadata prefix. for (const [key, value] of Object.entries(metadata)) { headers[`x-oss-meta-${key}`] = value; } // Read the file stream const fileStream = fs.createReadStream(filePath); // Send a PUT request const response = await axios.put(signedUrl, fileStream, { headers: headers }); console.log(`Status code: ${response.status}`); if (response.status === 200) { console.log("The object is uploaded by using the network library"); } else { console.log("Upload failed"); } console.log(response.data); } catch (error) { console.error(`An error occurred: ${error.message}`); } } // Specify the main function (async () => { // Replace with the signed URL. const signedUrl = ""; // Specify the full path of the local file. By default, if you do not specify the full path of a local file, the local file is uploaded from the directory in which the script is stored. const filePath = "C:\\Users\\demo.txt"; // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated. const headers = { "Content-Type": "text/plain;charset=utf8", "x-oss-storage-class": "Standard" }; // Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated. const metadata = { "key1": "value1", "key2": "value2" }; await uploadFile(signedUrl, filePath, headers, metadata); })();
Browser.js
ImportantWhen you use Browser.js code to upload an object based on a presigned URL, you may encounter a 403 error that indicates a signature inconsistency. This error arises from a signature verification failure, which occurs because the browser automatically adds the Content-Type request header, an element that was not specified when the presigned URL was generated. To resolve the error, you must specify the Content-Type header when you generate a presigned URL that is expected to be used in Browser.js code to upload data to OSS.
C++
#include <iostream> #include <fstream> #include <curl/curl.h> #include <map> #include <string> // Callback function that is used to process the HTTP response size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { size_t totalSize = size * nmemb; output->append((char*)contents, totalSize); return totalSize; } void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) { CURL* curl; CURLcode res; std::string readBuffer; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Specify the signed URL curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str()); // Set the request method to PUT curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // Open the local file FILE* file = fopen(filePath.c_str(), "rb"); if (!file) { std::cerr << "Unable to open the local file: " << filePath << std::endl; return; } // Specify the size of the local file fseek(file, 0, SEEK_END); long fileSize = ftell(file); rewind(file); // Configure a file read callback curl_easy_setopt(curl, CURLOPT_READDATA, file); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize); // Specify request headers struct curl_slist* chunk = nullptr; for (const auto& header : headers) { std::string headerStr = header.first + ": " + header.second; chunk = curl_slist_append(chunk, headerStr.c_str()); } for (const auto& meta : metadata) { std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second; chunk = curl_slist_append(chunk, metaStr.c_str()); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); // Specify the callback function that is used to process the response curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); // Execute the request res = curl_easy_perform(curl); // Check the response if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long responseCode; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); std::cout << "Upload status code: " << responseCode << std::endl; if (responseCode == 200) { std::cout << "The object is uploaded by using the network library." << std::endl; } else { std::cout << "Upload failed." << std::endl; } std::cout << readBuffer << std::endl; } // Clean up fclose(file); curl_slist_free_all(chunk); curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // Replace <signedUrl> with the presigned URL. std::string signedUrl = "<signedUrl>"; // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. std::string filePath = "C:\\Users\\demo.txt"; // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated. std::map<std::string, std::string> headers = { {"Content-Type", "text/plain;charset=utf8"}, {"x-oss-storage-class", "Standard"} }; // Specify user metadata. Make sure that the user metadata here is the same as the user metadata specified when the presigned URL was generated. std::map<std::string, std::string> metadata = { {"key1", "value1"}, {"key2", "value2"} }; uploadFile(signedUrl, filePath, headers, metadata); return 0; }
Android
import android.os.AsyncTask; import android.util.Log; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class SignUrlUploadActivity extends AppCompatActivity { private static final String TAG = "SignUrlUploadActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Replace <signedUrl> with the presigned URL. String signedUrl = "<signedUrl>"; // Specify the full path of the local file. By default, if you do not specify the full path, the local file is uploaded from the path of the project to which the sample program belongs. String pathName = "/storage/emulated/0/demo.txt"; // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated. Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "text/plain;charset=utf8"); headers.put("x-oss-storage-class", "Standard"); // Specify user metadata. Make sure that the user metadata here is the same as the user metadata specified when the presigned URL was generated. Map<String, String> userMetadata = new HashMap<>(); userMetadata.put("key1", "value1"); userMetadata.put("key2", "value2"); new UploadTask().execute(signedUrl, pathName, headers, userMetadata); } private class UploadTask extends AsyncTask<Object, Void, Integer> { @Override protected Integer doInBackground(Object... params) { String signedUrl = (String) params[0]; String pathName = (String) params[1]; Map<String, String> headers = (Map<String, String>) params[2]; Map<String, String> userMetadata = (Map<String, String>) params[3]; try { URL url = new URL(signedUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("PUT"); connection.setDoOutput(true); connection.setUseCaches(false); // Specify request headers for (Entry<String, String> header : headers.entrySet()) { connection.setRequestProperty(header.getKey(), header.getValue()); } // Specify user metadata for (Entry<String, String> meta : userMetadata.entrySet()) { connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue()); } // Read the local file File file = new File(pathName); FileInputStream fileInputStream = new FileInputStream(file); DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); byte[] buffer = new byte[1024]; int count; while ((count = fileInputStream.read(buffer)) != -1) { dos.write(buffer, 0, count); } fileInputStream.close(); dos.flush(); dos.close(); // Obtain the response int responseCode = connection.getResponseCode(); Log.d(TAG, "Upload status code: " + responseCode); if (responseCode == 200) { Log.d(TAG, "The object is uploaded by using the network library"); } else { Log.d(TAG, "Upload failed"); } InputStream is = connection.getInputStream(); byte[] responseBuffer = new byte[1024]; StringBuilder responseStringBuilder = new StringBuilder(); while ((count = is.read(responseBuffer)) != -1) { responseStringBuilder.append(new String(responseBuffer, 0, count)); } Log.d(TAG, responseStringBuilder.toString()); return responseCode; } catch (IOException e) { e.printStackTrace(); return -1; } } @Override protected void onPostExecute(Integer result) { super.onPostExecute(result); if (result == 200) { Toast.makeText(SignUrlUploadActivity.this, "Object uploaded", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(SignUrlUploadActivity.this, "Upload failed", Toast.LENGTH_SHORT).show(); } } } }
Configure upload callback
When uploading an object, you can include a callback parameter into the presigned URL to automatically notify your application server once the upload is complete. For more information about how callbacks work, see Callback.
The object owner generates a presigned URL (with the PUT method) containing the required upload callback parameters.
Python
import argparse import requests import alibabacloud_oss_v2 as oss from datetime import datetime, timedelta # Create a command line parameter parser and describe the purpose of the script. The example describes how to generate a presigned URL that allows HTTP PUT requests. parser = argparse.ArgumentParser(description="presign put object sample") # Specify the command line parameters, including the required region, bucket name, endpoint, and object name. parser.add_argument('--region', help='The region in which the bucket is located.', required=True) parser.add_argument('--bucket', help='The name of the bucket.', required=True) parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS') parser.add_argument('--key', help='The name of the object.', required=True) def main(): # Parse the command line parameters to obtain the values specified by the user. args = parser.parse_args() # Obtain access credentials from environment variables for authentication. credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() # Use the default configurations of the SDK to create a configuration object and specify the credential provider. cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider # Specify the region attribute of the configuration object based on the command line parameters specified by the user. cfg.region = args.region # If a custom endpoint is provided, modify the endpoint parameter in the configuration object. if args.endpoint is not None: cfg.endpoint = args.endpoint # Use the preceding configurations to initialize the OSSClient instance and allow the instance to interact with OSS. client = oss.Client(cfg) # Send the request to initiate a PUT request and generate a presigned URL for the specified object. pre_result = client.presign(oss.PutObjectRequest( bucket=args.bucket, # The name of the bucket. key=args.key, # The name of the object. content_type='text/plain;charset=utf8', # Specify the type of the object. storage_class='Standard', # Specify the storage class of the object. metadata={ 'key1': 'value1', # Specify the metadata of the object. 'key2': 'value2' # Specify the metadata of the object. } ),expires=timedelta(seconds=3600)) # Specify the validity period of the request. In this example, the validity period is set to 3,600 seconds. # Display the method, expiration time, and presigned URL specified in the request to check the validity of the presigned URL. print(f'method: {pre_result.method},' f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},' f' url: {pre_result.url}' ) # Display the signed headers in the request, which are included in the HTTP header when the request is sent. for key, value in pre_result.signed_headers.items(): print(f'signed headers key: {key}, signed headers value: {value}') # Call the main function to start the processing logic when the script is directly run. if __name__ == "__main__": main() # Specify the entry points in the functions of the script. The control program flow starts here.
Go
package main import ( "context" "encoding/base64" "encoding/json" "flag" "log" "time" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" ) // Define global variables. var ( region string // The region in which the bucket is located. bucketName string // The name of the bucket. objectName string // The name of the object. ) // Define the init function to initialize the command-line parameters. func init() { flag.StringVar(®ion, "region", "", "The region in which the bucket is located.") flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.") flag.StringVar(&objectName, "object", "", "The name of the object.") } func main() { // Parse the command-line parameters. flag.Parse() // Check whether the bucket name is empty. if len(bucketName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, bucket name required") } // Check whether the region is empty. if len(region) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, region required") } // Check whether the object name is empty. if len(objectName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, object name required") } // Load the default configurations and specify the credential provider and region. cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region) // Create an OSS client. client := oss.NewClient(cfg) // Specify the callback parameters. callbackMap := map[string]string{ "callbackUrl": "http://example.com:23450", // Specify the URL of the callback server, such as https://example.com:23450. "callbackBody": "bucket=${bucket}&object=${object}&size=${size}&my_var_1=${x:my_var1}&my_var_2=${x:my_var2}", // Specify the callback request body. "callbackBodyType": "application/x-www-form-urlencoded", // Specify the Content-Type of the callback request body. } // Convert the callback parameter configurations into a JSON string, then Base64-encode it to pass the callback settings. callbackStr, err := json.Marshal(callbackMap) if err != nil { log.Fatalf("failed to marshal callback map: %v", err) } callbackBase64 := base64.StdEncoding.EncodeToString(callbackStr) callbackVarMap := map[string]string{} callbackVarMap["x:my_var1"] = "thi is var 1" callbackVarMap["x:my_var2"] = "thi is var 2" callbackVarStr, err := json.Marshal(callbackVarMap) if err != nil { log.Fatalf("failed to marshal callback var: %v", err) } callbackVarBase64 := base64.StdEncoding.EncodeToString(callbackVarStr) // Generate a presigned URL with the PutObject method. result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), Callback: oss.Ptr(callbackBase64), // Specify the callback parameters, which are Base64-encoded JSON strings. CallbackVar: oss.Ptr(callbackVarBase64), // Specify the custom callback parameters, which are Base64-encoded JSON strings. }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("failed to put object presign %v", err) } log.Printf("request method:%v\n", result.Method) log.Printf("request expiration:%v\n", result.Expiration) log.Printf("request url:%v\n", result.URL) if len(result.SignedHeaders) > 0 { // When the response includes signature headers, you must set the corresponding request headers when sending a PUT request with the presigned URL. log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
Java
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.internal.OSSHeaders; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import java.net.URL; import java.text.SimpleDateFormat; import java.util.*; public class OssPresignExample { public static void main(String[] args) throws Throwable { // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // Specify the name of the bucket. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object. Example: exampleobject.txt. Do not include the bucket name in the full path. String objectName = "exampleobject.txt"; // Specify the region in which the bucket is located. For example, if your bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. String region = "cn-hangzhou"; // Create an OSSClient instance. // Call the shutdown method to release resources when the OSSClient is no longer in use. ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); URL signedUrl = null; try { // Construct a callback parameter. String callbackUrl = "http://www.example.com/callback"; String callbackBody = "{\"callbackUrl\":\"" + callbackUrl + "\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}"; String callbackBase64 = Base64.getEncoder().encodeToString(callbackBody.getBytes()); String callbackVarJson = "{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}"; String callbackVarBase64 = Base64.getEncoder().encodeToString(callbackVarJson.getBytes()); // Specify request headers. Map<String, String> headers = new HashMap<String, String>(); // Specify the CALLBACK parameter. headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64); // Specify the CALLBACK-VAR parameter. headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64); // Set the validity period (3600 seconds). Date expiration = new Date(new Date().getTime() + 3600 * 1000); // Specify the format for the expiration time. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); String expirationStr = dateFormat.format(expiration); // Construct a request. GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName); request.setMethod(HttpMethod.PUT); request.setExpiration(expiration); // Add headers to the request. request.setHeaders(headers); // Output the callback parameter and the callback-var parameter. System.out.println("callback:"+callbackBase64); System.out.println("callback-var:"+callbackVarBase64); // Generate a presigned URL. URL url = ossClient.generatePresignedUrl(request); // Output the result. System.out.println("method: PUT,"); System.out.println(" expiration: " + expirationStr + ","); System.out.println(" url: " + url); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } } }
PHP
<?php // Include the autoload file so that the required dependencies can be loaded. require_once __DIR__ . '/../vendor/autoload.php'; use AlibabaCloud\Oss\V2 as Oss; // Specify descriptions for command line arguments. $optsdesc = [ "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located. "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // (Optional) Specify the endpoint that can be used by other services to access OSS. "bucket" => ['help' => 'The name of the bucket', 'required' => True], // (Required) Specify the name of the bucket. "key" => ['help' => 'The name of the object', 'required' => True], // (Required) Specify the name of the object. ]; // Convert the descriptions to a list of long options required by getopt. // Add a colon (:) to the end of each parameter to indicate that a value is required. $longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc)); // Parse the command-line parameters. $options = getopt("", $longopts); // Check whether the required parameters are provided. foreach ($optsdesc as $key => $value) { if ($value['required'] === True && empty($options[$key])) { $help = $value['help']; // Get the help information for the parameter echo "Error: the following arguments are required: --$key, $help" . PHP_EOL; exit(1); // Exit the program if the required parameters are not configured. } } // Obtain values from the parsed parameters. $region = $options["region"]; // The region in which the bucket is located $bucket = $options["bucket"]; // The name of the bucket $key = $options["key"]; // The name of the object // Load access credentials from environment variables. // Use EnvironmentVariableCredentialsProvider to retrieve the AccessKey ID and AccessKey secret from environment variables. $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider(); // Use the default configurations of the SDK. $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider($credentialsProvider); // Set the credentials provider $cfg->setRegion($region); // Set the region in which the bucket is located if (isset($options["endpoint"])) { $cfg->setEndpoint($options["endpoint"]); // Set the endpoint if provided } // Create an OSS client instance. $client = new Oss\Client($cfg); // Add x-oss-callback and x-oss-callback-var headers // Define the webhook address $call_back_url = "http://www.example.com/callback"; // Construct callback parameters: specify the webhook address and request body, and use Base64 encoding // Use placeholders {var1} and {var2} to replace ${x:var1} and ${x:var2} $callback_body_template = "bucket={bucket}&object={object}&my_var_1={var1}&my_var_2={var2}"; $callback_body_replaced = str_replace( ['{bucket}', '{object}', '{var1}', '{var2}'], [$bucket, $key, 'value1', 'value2'], $callback_body_template ); $callback = base64_encode(json_encode([ "callbackUrl" => $call_back_url, "callbackBody" => $callback_body_replaced ])); // Construct custom variables (callback-var) using Base64 encoding $callback_var = base64_encode(json_encode([ "x:var1" => "value1", "x:var2" => "value2" ])); // Create a PutObjectRequest object to upload the object. // Note: contentType, metadata, and headers parameters are added here for signature calculation. $request = new Oss\Models\PutObjectRequest( bucket: $bucket, key: $key, callback:$callback, callbackVar:$callback_var, ); // Call the presign method to generate a presigned URL. $result = $client->presign($request); // Print the presigned result, output the presigned URL that users can directly use to upload objects print( 'put object presign result:' . var_export($result, true) . PHP_EOL . 'put object url:' . $result->url . PHP_EOL );
Others upload objects by using the presigned URL with the PUT method.
curl
curl -X PUT -T /path/to/local/file "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"
Java
import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import java.io.*; import java.net.URL; import java.util.*; public class SignUrlUpload { public static void main(String[] args) throws Throwable { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; // Replace <signedUrl> with the presigned URL. URL signedUrl = new URL("<signedUrl>"); // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. String pathName = "C:\\Users\\demo.txt"; try { HttpPut put = new HttpPut(signedUrl.toString()); System.out.println(put); HttpEntity entity = new FileEntity(new File(pathName)); put.setEntity(entity); httpClient = HttpClients.createDefault(); response = httpClient.execute(put); System.out.println("Status code:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("The object is uploaded by using the library."); } System.out.println(response.toString()); } catch (Exception e){ e.printStackTrace(); } finally { response.close(); httpClient.close(); } } }
Go
package main import ( "fmt" "io" "net/http" "os" ) func uploadFile(signedUrl, filePath string) error { // Open the local file. file, err := os.Open(filePath) if err != nil { return fmt.Errorf("Unable to open the local file: %w", err) } defer file.Close() // Create an HTTP client. client := &http.Client{} // Create a PUT request. req, err := http.NewRequest("PUT", signedUrl, file) if err != nil { return fmt.Errorf("Failed to create the request: %w", err) } // Send the request. resp, err := client.Do(req) if err != nil { return fmt.Errorf("Failed to send the request:: %w", err) } defer resp.Body.Close() // Read the response. body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Failed to read the request: %w", err) } fmt.Printf("Status code: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("The object is uploaded by using the library.") } fmt.Println(string(body)) return nil } func main() { // Replace <signedUrl> with the presigned URL. signedUrl := "<signedUrl>" // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. filePath := "C:\\Users\\demo.txt" err := uploadFile(signedUrl, filePath) if err != nil { fmt.Println("An error occurred: ", err) } }
python
import requests def upload_file(signed_url, file_path): try: # Open the local file that you want to upload. with open(file_path, 'rb') as file: # Send a PUT request to upload the local file. response = requests.put(signed_url, data=file) print(f"Status code: {response.status_code}") if response.status_code == 200: print("The object is uploaded by using the library.") print(response.text) except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": # Replace <signedUrl> with the generated signed URL. signed_url = "<signedUrl>" # Specify the full path of the local file. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. file_path = "C:\\Users\\demo.txt" upload_file(signed_url, file_path)
Node.js
const fs = require('fs'); const axios = require('axios'); async function uploadFile(signedUrl, filePath) { try { // Create a read stream. const fileStream = fs.createReadStream(filePath); // Send a PUT request to upload the local file. const response = await axios.put(signedUrl, fileStream, { headers: { 'Content-Type': 'application/octet-stream' // Specify the Content-Type parameter. } }); console.log(`Status code: ${response.status}`); if (response.status === 200) { console.log("The object is uploaded by using the library."); } console.log(response.data); } catch (error) { console.error(`An error occurred: ${error.message}`); } } // Specify the main function. (async () => { // Replace <signedUrl> with the presigned URL. const signedUrl = '<signedUrl>'; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();
browser.js
ImportantWhen uploading an object using Browser.js and a presigned URL, a 403 SignatureNotMatch error that indicates signature inconsistency may occur. This is typically caused by the browser's automatic inclusion of the Content-Type request header, which that was not specified when the presigned URL was generated. To prevent this error, ensure that the Content-Type header is specified when generating a presigned URL.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload Example</title> </head> <body> <h1>File Upload Example</h1> <! -- Select File --> <input type="file" id="fileInput" /> <button id="uploadButton">Upload File</button> <script> // Replace <signedUrl> with the presigned URL that was generated in Step 1. const signedUrl = "<signedUrl>"; document.getElementById('uploadButton').addEventListener('click', async () => { const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('Please select a file to upload.'); return; } try { await upload(file, signedUrl); alert('File uploaded successfully!'); } catch (error) { console.error('Error during upload:', error); alert('Upload failed: ' + error.message); } }); /** * Upload a file to OSS. * @param {File} file - The file to be uploaded. * @param {string} presignedUrl - The presigned URL. */ const upload = async (file, presignedUrl) => { const response = await fetch(presignedUrl, { method: 'PUT', body: file, // Upload the entire file. }); if (!response.ok) { throw new Error(`Upload failed, status: ${response.status}`); } console.log('File uploaded successfully'); }; </script> </body> </html>
C++
#include <iostream> #include <fstream> #include <curl/curl.h> void uploadFile(const std::string& signedUrl, const std::string& filePath) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Specify the presigned URL. curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str()); // Set the request method to PUT. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // Open the local file. FILE *file = fopen(filePath.c_str(), "rb"); if (!file) { std::cerr << "Unable to open the file: " << filePath << std::endl; return; } // Query the size of the local file. fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); // Specify the size of the local file. curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize); // Specify the input file handle. curl_easy_setopt(curl, CURLOPT_READDATA, file); // Execute the request. res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long httpCode = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); std::cout << "Status code: " << httpCode << std::endl; if (httpCode == 200) { std::cout << "The object is uploaded by using the network library." << std::endl; } } // Close the local file. fclose(file); // Clear the cURL handle. curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // Replace <signedUrl> with the presigned URL. std::string signedUrl = "<signedUrl>"; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. std::string filePath = "C:\\Users\\demo.txt"; uploadFile(signedUrl, filePath); return 0; }
Android
package com.example.signurlupload; import android.os.AsyncTask; import android.util.Log; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; public class SignUrlUploadActivity { private static final String TAG = "SignUrlUploadActivity"; public void uploadFile(String signedUrl, String filePath) { new UploadTask().execute(signedUrl, filePath); } private class UploadTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { String signedUrl = params[0]; String filePath = params[1]; HttpURLConnection connection = null; DataOutputStream dos = null; FileInputStream fis = null; try { URL url = new URL(signedUrl); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("PUT"); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/octet-stream"); fis = new FileInputStream(filePath); dos = new DataOutputStream(connection.getOutputStream()); byte[] buffer = new byte[1024]; int length; while ((length = fis.read(buffer)) != -1) { dos.write(buffer, 0, length); } dos.flush(); dos.close(); fis.close(); int responseCode = connection.getResponseCode(); Log.d(TAG, "Status code: " + responseCode); if (responseCode == 200) { Log.d(TAG, "The object is uploaded by using the library."); } return "Object uploaded. Status code: " + responseCode; } catch (IOException e) { e.printStackTrace(); return "Upload failed: " + e.getMessage(); } finally { if (connection != null) { connection.disconnect(); } } } @Override protected void onPostExecute(String result) { Log.d(TAG, result); } } public static void main(String[] args) { SignUrlUploadActivity activity = new SignUrlUploadActivity(); // Replace <signedUrl> with the presigned URL. String signedUrl = "<signedUrl>"; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. String filePath = "C:\\Users\\demo.txt"; activity.uploadFile(signedUrl, filePath); } }
Additional information
What is a presigned URL?
A presigned URL is a time-limited, secure link that grants temporary access to a specific object in OSS. To generate a presigned URL, the client creates a cryptographic signature by using the AccessKey pair, resource path, and expiration time. This signature is added to the original URL, producing a time-limited access link. The typical format of a presigned URL is https://BucketName.Endpoint/Object?Signature
.
When a third party accesses the presigned URL, OSS validates the signature. If the signature is invalid or expired, access is rejected.
Sample presigned URL:
https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-process=image%2Fresize%2Cp_10&x-oss-date=20241115T095058Z&x-oss-expires=3600&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241115%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=6e7a********************************
With this method, object owners can safely provide limited access to third parties, without ever revealing their private keys.
Applicable scenarios
Temporary object sharing: To allow a third party to securely upload or download a specific object, the backend generates a time-limited presigned URL and provides it to the frontend. The third party can then use this URL to perform the operation within the allowed timeframe, ensuring controlled and secure data access.
Flexible object sharing: Object owners can securely share their objects by generating presigned URLs and distributing them via email or messaging apps to third parties. Recipients simply paste the URLs into their browser to download the desired objects.