Download an object using a presigned URL

Updated at:

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 Python to generate a presigned URL that allows a user to download a specific object within a specified period using the HTTP GET method. Within the validity period, the user can repeatedly access the object using the presigned URL. If the presigned URL expires, you can regenerate a presigned URL to extend access for the user.

Usage notes

  • For more information about the mapping between regions and endpoints supported by OSS, see OSS regions and endpoints.

  • When you generate a presigned URL that allows HTTP GET requests, you must have the oss:GetObject permission. For more information, see Grant custom permissions to a RAM user.

    Note

    When you use OSS SDK for Python to generate a signed URL, the SDK uses a specific algorithm based on the key information stored in the local computer to calculate a signature and adds the signature to a URL to ensure the validity and security of the URL. Signature calculation and URL construction are performed on the client side and do not involve sending requests to the server over the network. Therefore, you do not need specific permissions to generate a presigned URL. However, to allow third-party users to perform intended operations on a resource, make sure that the identity principal that generates the presigned URL has the corresponding permissions to perform the operations.

  • 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 flowchart shows how to download an object using a presigned URL.

image

Sample code

  1. Generate a presigned URL that allows HTTP GET requests:

    import Client from '@aliyun/oss';
    
    // Create an OSS client instance
    const client = new Client({
      // Specify the AccessKey ID obtained from Security Token Service (STS).
      accessKeyId: 'yourAccessKeyId',
      // Specify the AccessKey secret obtained from STS.
      accessKeySecret: 'yourAccessKeySecret',
      // Specify the security token obtained from STS.
      securityToken: 'yourSecurityToken',
      // Specify the region of the bucket that you want to access. For example, if the bucket is located in the China (Hangzhou) region, set the region to oss-cn-hangzhou.
      region: 'oss-cn-hangzhou',
    });
    
    // Specify the name of the bucket.
    const bucket = 'yourBucketName';
    // Specify the name of the object for which you want to generate a signed URL.
    const key = 'yourObjectName';
    
    /**
     * Generate a signed URL to get an object.
     * Use the signatureUrl method to generate a signed URL for a GET request, using Client.options.signVersion by default.
     */
    const signatureUrlForGetObject = async () => {
      /**
       * If no signature version is explicitly specified, Client.options.signVersion is used by default.
       */
      const url = await client.signatureUrl({
        bucket, // Specify the name of the bucket.
        key,    // Specify the name of the object.
        expires: 60 * 60, // Set the expiration time to 60 minutes (in seconds).
      });
    
      // Print the generated signed URL
      console.log(url);
    };
    
    signatureUrlForGetObject();
    
  2. 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

Download an object using a presigned URL with specific request headers

If you specify request headers when you generate a presigned URL that allows HTTP GET requests, make sure that the request headers are included in the GET request initiated using the presigned URL. This prevents request failures and signature errors.

  1. Generate a presigned URL that contains specific request headers and allows HTTP GET requests.

    import Client, { EHeaderKey } from '@aliyun/oss';
    
    // Create an OSS client instance
    const client = new Client({
      // Specify the AccessKey ID obtained from Security Token Service (STS).
      accessKeyId: 'yourAccessKeyId',
      // Specify the AccessKey secret obtained from STS.
      accessKeySecret: 'yourAccessKeySecret',
      // Specify the security token obtained from STS.
      securityToken: 'yourSecurityToken',
      // Specify the region of the bucket that you want to access. For example, if the bucket is located in the China (Hangzhou) region, set the region to oss-cn-hangzhou.
      region: 'oss-cn-hangzhou',
    });
    
    // Specify the name of the bucket.
    const bucket = 'yourBucketName';
    // Specify the name of the object for which you want to generate a signed URL.
    const key = 'yourObjectName';
    
    /**
     * Generate a signed URL to get an object.
     * Use the signatureUrl method to generate a signed URL for a GET request, using Client.options.signVersion by default.
     */
    const signatureUrlForGetObject = async () => {
      /**
       * If no signature version is explicitly specified, Client.options.signVersion is used by default.
       */
      const url = await client.signatureUrl({
        bucket, // Specify the name of the bucket.
        key,    // Specify the name of the object.
        expires: 60 * 60, // Set the expiration time to 60 minutes (in seconds).
        headers: {
          [EHeaderKey.RANGE]: 'bytes=0-1024', // Set the Range header.
        },
      });
    
      // Print the generated signed URL
      console.log(url);
    };
    
    signatureUrlForGetObject();
    
  2. Download the object using the presigned URL and specifying the request headers:

    curl -X GET "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241113T093321Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************&x-oss-signature=ed5a******************************************************" \
    -H "Range: bytes=0-1024" \
    -o "myfile.txt"