By default, the access control list (ACL) of an object in an Object Storage Service (OSS) bucket is private. Only the object owner has the permissions to access the object. This topic describes how to use OSS SDK for Python to generate a presigned URL that allows a user to download a specific object within the specified period by using the HTTP GET method. Within the validity period, the user can repeatedly access the object by using the presigned URL. If the presigned URL expires, you can regenerate a presigned URL to prolong access for the user.
Usage notes
-
The sample code in this topic uses the region ID
cn-hangzhouof the China (Hangzhou) region. By default, the public endpoint is used to access resources in a bucket. If you want to access resources in the bucket from other Alibaba Cloud services in the same region in which the bucket is located, use the internal endpoint. For more information about OSS regions and endpoints, see Regions and endpoints. -
You do not need permissions to generate a presigned URL. However, for a third party to download the object using the presigned URL, the user who generates the URL must have the
oss:GetObjectpermission. For more information about how to grant permissions, see Grant custom permissions to a RAM user. -
In this topic, the signature algorithm V4 is used to generate presigned URLs with a validity period of up to 7 days. For more information, see (Recommended) V4 signatures in presigned URLs.
Procedure
The following procedure describes how to download an object using a presigned URL:
Method definition
You can call the presign method to generate a presigned URL that grants time-limited access to an OSS object. The presigned URL can be used multiple times before it expires.
The following line shows the syntax of the presign method:
presign(request: GetObjectRequest, **kwargs) → PresignResult
Request parameters
|
Parameter |
Type |
Description |
|
request |
GetObjectRequest |
The API operation that you want the presigned URL to support. For more information, see Client.presign. |
|
expires |
datetime.timedelta |
The validity period of the presigned URL starting from the current time. This is an optional parameter. For example, if you want to set the validity period to 30 minutes, set expires to 30 * time.Minute. If you do not specify this parameter, the presigned URL will have a default validity period of 15 minutes. |
|
expiration |
datetime.datetime |
The absolute expiration date and time of the presigned URL. This is an optional parameter. |
If you use the V4 signature algorithm, the validity period can be up to seven days. If you specify both expiration and expires, expiration takes precedence.
Response parameters
|
Type |
Description |
|
PresignResult |
The returned results, including the presigned URL, HTTP method, expiration time, and request headers specified in the request. For more information, see PresignResult. |
Content of PresignResult
|
Parameter |
Type |
Description |
|
method |
str |
The HTTP method, which corresponds to the API operation specified in the presign request. For example, the HTTP method of the GetObject operation is GET. |
|
url |
str |
The presigned URL. |
|
expiration |
datetime |
The expiration time of the presigned URL. |
|
signed_headers |
MutableMapping |
The signed headers specified in the request. For example, if content_type is specified, content_type is returned. |
For the more information about the presign method, see presign.
Sample code
-
Generate a presigned URL that allows HTTP GET requests:
import argparse import alibabacloud_oss_v2 as oss # Create a command-line parameter parser and describe the purpose of the script. parser = argparse.ArgumentParser(description="presign get object sample") # Specify the --region parameter to indicate the region in which the bucket is located. This parameter is required. parser.add_argument('--region', help='The region in which the bucket is located.', required=True) # Specify the --bucket parameter to indicate the name of the bucket in which the object is stored. This parameter is required. parser.add_argument('--bucket', help='The name of the bucket.', required=True) # Specify the --endpoint parameter to indicate the endpoint of the region in which the bucket is located. This parameter is optional. parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS') # Specify the --key parameter to indicate the name of the object. This parameter is required. parser.add_argument('--key', help='The name of the object.', required=True) def main(): # Parse the command-line parameters to obtain the specified values. args = parser.parse_args() # From the environment variables, load the authentication information required to access OSS. credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() # Use the default configuration to create a cfg object and specify the credential provider. cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider # Set the region attribute of the cfg object to the region provided in the command line. cfg.region = args.region # If a custom endpoint is provided, update the endpoint attribute of the cfg object with the provided endpoint. if args.endpoint is not None: cfg.endpoint = args.endpoint # Use the preceding settings to initialize the OSSClient instance. client = oss.Client(cfg) # Initiate a request to generate a presigned URL. pre_result = client.presign( oss.GetObjectRequest( bucket=args.bucket, # Specify the bucket name. key=args.key, # Specify the object key. ) ) # Display the HTTP method, expiration time, and 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. 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 point of the script. The control flow starts here. -
Use the presigned URL to download the object.
curl
curl -SO "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"Java
import java.io.BufferedInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class Demo { public static void main(String[] args) { // Replace with the generated presigned URL for the GET request. String fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; // Enter the destination path to save the file, including the file name and extension. String savePath = "C:/downloads/myfile.txt"; try { downloadFile(fileURL, savePath); System.out.println("Download completed!"); } catch (IOException e) { System.err.println("Error during download: " + e.getMessage()); } } private static void downloadFile(String fileURL, String savePath) throws IOException { URL url = new URL(fileURL); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestMethod("GET"); // Check the response code. int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // Input stream. InputStream inputStream = new BufferedInputStream(httpConn.getInputStream()); // Output stream. FileOutputStream outputStream = new FileOutputStream(savePath); byte[] buffer = new byte[4096]; // Buffer. int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.close(); inputStream.close(); } else { System.out.println("No file to download. Server replied HTTP code: " + responseCode); } httpConn.disconnect(); } }Node.js
const https = require('https'); const fs = require('fs'); const fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; const savePath = "C:/downloads/myfile.txt"; https.get(fileURL, (response) => { if (response.statusCode === 200) { const fileStream = fs.createWriteStream(savePath); response.pipe(fileStream); fileStream.on('finish', () => { fileStream.close(); console.log("Download completed!"); }); } else { console.error(`Download failed. Server responded with code: ${response.statusCode}`); } }).on('error', (err) => { console.error("Error during download:", err.message); });Python
import requests file_url = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************" save_path = "C:/downloads/myfile.txt" try: response = requests.get(file_url, stream=True) if response.status_code == 200: with open(save_path, 'wb') as f: for chunk in response.iter_content(4096): f.write(chunk) print("Download completed!") else: print(f"No file to download. Server replied HTTP code: {response.status_code}") except Exception as e: print("Error during download:", e)Go
package main import ( "io" "net/http" "os" ) func main() { fileURL := "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************" savePath := "C:/downloads/myfile.txt" response, err := http.Get(fileURL) if err != nil { panic(err) } defer response.Body.Close() if response.StatusCode == http.StatusOK { outFile, err := os.Create(savePath) if err != nil { panic(err) } defer outFile.Close() _, err = io.Copy(outFile, response.Body) if err != nil { panic(err) } println("Download completed!") } else { println("No file to download. Server replied HTTP code:", response.StatusCode) } }JavaScript
const fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; const savePath = "C:/downloads/myfile.txt"; // The file name to use for the download. fetch(fileURL) .then(response => { if (!response.ok) { throw new Error(`Server replied HTTP code: ${response.status}`); } return response.blob(); // Convert the response to a blob. }) .then(blob => { const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = savePath; // Set the name of the downloaded file. document.body.appendChild(link); // This step ensures that the link exists in the document. link.click(); // Simulate a click on the download link. link.remove(); // Remove the link after completion. console.log("Download completed!"); }) .catch(error => { console.error("Error during download:", error); });Android-Java
import android.os.AsyncTask; import android.os.Environment; import java.io.BufferedInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class DownloadTask extends AsyncTask<String, String, String> { @Override protected String doInBackground(String... params) { String fileURL = params[0]; String savePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/myfile.txt"; // The modified save path. try { URL url = new URL(fileURL); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestMethod("GET"); int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { InputStream inputStream = new BufferedInputStream(httpConn.getInputStream()); FileOutputStream outputStream = new FileOutputStream(savePath); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.close(); inputStream.close(); return "Download completed!"; } else { return "No file to download. Server replied HTTP code: " + responseCode; } } catch (Exception e) { return "Error during download: " + e.getMessage(); } } }Objective-C
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // Define the file URL and save path (change to a valid path). NSString *fileURL = @"https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; NSString *savePath = @"/Users/your_username/Desktop/myfile.txt"; // Replace with your username. // Create a URL object. NSURL *url = [NSURL URLWithString:fileURL]; // Create a download task. NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // Error handling. if (error) { NSLog(@"Error during download: %@", error.localizedDescription); return; } // Check the data. if (!data) { NSLog(@"No data received."); return; } // Save the file. NSError *writeError = nil; BOOL success = [data writeToURL:[NSURL fileURLWithPath:savePath] options:NSDataWritingAtomic error:&writeError]; if (success) { NSLog(@"Download completed!"); } else { NSLog(@"Error saving file: %@", writeError.localizedDescription); } }]; // Start the task. [task resume]; // Keep the main thread running so that the asynchronous request can be completed. [[NSRunLoop currentRunLoop] run]; } return 0; }
Common scenarios
Generate a presigned URL that allows HTTP GET requests for a specific version of an object
Download an object by using a presigned URL that contains specified request headers
Forcibly download an object by using a presigned URL
Generate a presigned URL that allows object downloads by using a custom endpoint
References
-
For the complete sample code for downloading an object by using a presigned URL, see presigner_get_object.py.