By default, the access control list (ACL) of an object in an Object Storage Service (OSS) bucket is private. Only the object owner has permissions to access the object. This topic describes how to use OSS SDK for Go to generate a signed URL that allows HTTP GET requests and has an expiration time. This allows others to temporarily download the object. Within the validity period, users can repeatedly access the object by using the presigned URL. If the presigned URL expires, you can regenerate a presigned URL to extend access for the user.
Notes
In this topic, the region ID
cn-hangzhou
of China (Hangzhou) is used as an example. By default, the public endpoint is used. If you want to access OSS from other Alibaba Cloud services in the same region as OSS, use the internal endpoint. For more information about the mappings between regions and endpoints supported by OSS, see Regions and endpoints.In this topic, access credentials obtained from environment variables are used. For more information about how to configure access credentials, see Configure access credentials.
No specific permissions are required for the generation of presigned URLs. However, a pre-signed URL allows third-party users to download the object only if the creator of the URL has the
oss:GetObject
permission. For more information, see Attach a custom policy to a RAM user.In this topic, presigned URLs that include V4 signatures and have a validity period of up to seven days are used. For more information, see Signature version 4 (recommended).
Process
The following figure shows how to use a presigned URL to download an object.
Method definition
You can call the presign method to generate a presigned URL that grants time-limited access to an OSS object. You can use the pre-signed URL multiple times before the URL expires.
Syntax:
func (c *Client) Presign(ctx context.Context, request any, optFns ...func(*PresignOptions)) (result *PresignResult, err error)
Request parameters
Parameter | Type | Description |
ctx | context.Context | The context of the request. |
request | *GetObjectRequest | The name of the operation for which you want to generate a presigned URL. |
optFns | ...func(*PresignOptions) | The validity period of the signed URL. If you do not specify this parameter, the signed URL uses the default value, which is 15 minutes. This parameter is optional. |
PressignOptions
Option | Type | Description |
Expires | time.Duration | The validity period of the signed URL. For example, if you want to set the validity period to 30 minutes, set Expires to 30 * time.Minute. |
Expiration | time.Time | The absolute expiration time. |
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
Parameter | Type | Description |
result | *PresignResult | The result that contains the presigned URL, HTTP method, expiration time, and request headers that are included in the presigned URL. |
err | error | The status of the request. If the request fails, the value of err cannot be nil. |
Response parameters of PresignResult
Parameter | Type | Description |
Method | string | The HTTP method, which corresponds to the API operation specified in the presign request. For example, if you specify GetObject, the value of this response parameter is GET. |
URL | string | The presigned URL. |
Expiration | time.Time | The expiration time of the presigned URL. |
SignedHeaders | map[string]string | The signed request headers. For example, if you set Content-Type, the Content-Type information is returned. |
Sample code
Generate a presigned URL that allows HTTP GET requests:
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 the 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 used to initialize 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 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 in which the bucket is located 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) // Generate a signed URL for the GetObject request. result, err := client.Presign(context.TODO(), &oss.GetObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("failed to get 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 returned result contains signed headers, include the corresponding request headers when sending a GET request using the presigned URL to avoid inconsistencies that may lead to request failures and presigning errors. log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
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) { // Specify the presigned URL that allows HTTP GET requests. 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******************************************************"; // Specify the path in which the downloaded object is stored, including the object 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"); // Specify the response code. int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // Configure the input stream. InputStream inputStream = new BufferedInputStream(httpConn.getInputStream()); // Configure the output stream. FileOutputStream outputStream = new FileOutputStream(savePath); byte[] buffer=new byte[4096]; // Specify the size of the 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"; // Specify the name of the downloaded object. fetch(fileURL) .then(response => { if (!response.ok) { throw new Error(`Server replied HTTP code: ${response.status}`); } return response.blob(); // Change the type of the response to blob. }) .then(blob => { const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download=savePath; // Specify the name of the downloaded object. document.body.appendChild(link); // This step ensures that the link exists in the document. link.click(); // Click the link to simulate the download. link.remove(); // Remove the link after the object is downloaded. 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"; // Specify the path in which you want to store the downloaded object. 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 { // Specify the presigned URL and the path in which you want to store the object. 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 your_username with your actual username. // Create a URL object. NSURL *url = [NSURL URLWithString:fileURL]; // Create an object download task. NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // Handle errors. if (error) { NSLog(@"Error during download: %@", error.localizedDescription); return; } // Check the data of the object. if (!data) { NSLog(@"No data received."); return; } // Save the object. 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 object download task. [task resume]; // Continue to run the main thread to complete the asynchronous request. [[NSRunLoop currentRunLoop] run]; } return 0; }
Common scenarios
Generate a presigned URL for a specific version of an object
Download an object by using a presigned URL and specifying request headers
Force the download of a specific object by using a presigned URL
Generate a presigned URL for download by using a custom domain name
References
For the complete sample code about presigned URLs, see GitHub sample.
For more information about the API operation for presigned URLs, see Presign.