All Products
Search
Document Center

Object Storage Service:Download an object by using a signed URL (Go SDK V1)

Last Updated:Mar 20, 2026

Objects in an Object Storage Service (OSS) bucket are private by default. Use the Go software development kit (SDK) to generate a signed URL for a GET request, then share the URL so others can download the object without needing OSS credentials. The URL is reusable until it expires, after which you must generate a new one.

Prerequisites

Before you begin, ensure that you have:

  • An OSS bucket with at least one object to download

  • The oss:GetObject RAM permission on the target object (required to allow downloads via the signed URL; no special permission is needed to generate the URL itself)

  • The OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables configured. See Configure access credentials (Go SDK V1)

  • (Optional) An OSSClient instance initialized with a custom domain name or Security Token Service (STS). See Configuration examples for common scenarios

The examples in this topic use the public endpoint for the China (Hangzhou) region. To access OSS from another Alibaba Cloud service in the same region, use the internal endpoint instead. For a full list of regions and endpoints, see Regions and endpoints.

How it works

  1. The object owner initializes an OSSClient with V4 signing enabled.

  2. The owner calls bucket.SignURL to generate a signed URL for an HTTP GET request, with a specified expiry in seconds.

  3. The signed URL is shared with any user who needs to download the object.

  4. The recipient sends a GET request to the signed URL — no OSS credentials required.

  5. OSS validates the signature and returns the object if the URL is still within its validity period.

The maximum validity period for a V4 signed URL is 7 days (604,800 seconds). See Signature V4 (recommended).

Generate a signed URL

Initialize an OSSClient and call bucket.SignURL to generate a signed URL for downloading an object.

package main

import (
	"log"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
	// Read credentials from environment variables.
	// Make sure OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET are set before running this code.
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		log.Printf("Error: %v\n", err)
	}

	// Initialize an OSSClient with V4 signing.
	// Replace yourEndpoint with your bucket's endpoint, for example:
	//   China (Hangzhou): https://oss-cn-hangzhou.aliyuncs.com
	// Replace cn-hangzhou with the region where your bucket is located.
	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("cn-hangzhou"))
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
	client, err := oss.New("yourEndpoint", "", "", clientOptions...)
	if err != nil {
		log.Printf("Error: %v\n", err)
	}

	// Replace examplebucket with your bucket name.
	bucketName := "examplebucket"
	// Replace exampleobject.txt with the full object path (excluding the bucket name).
	objectName := "exampleobject.txt"

	bucket, err := client.Bucket(bucketName)
	if err != nil {
		log.Printf("Error: %v\n", err)
	}

	// Generate a signed URL valid for 600 seconds (10 minutes).
	// The third argument is the expiry in seconds (max: 604,800 for V4 signatures).
	signedURL, err := bucket.SignURL(objectName, oss.HTTPGet, 600)
	if err != nil {
		log.Printf("Error: %v\n", err)
	}
	log.Printf("Signed URL: %s\n", signedURL)
}

SignURL parameters

ParameterTypeDescription
objectNamestringFull object path within the bucket, excluding the bucket name. For example: exampleobject.txt or exampledir/exampleobject.txt
methodHTTPMethodHTTP method for the request. Use oss.HTTPGet to generate a download URL
expiredInSecint64URL validity period in seconds. Maximum: 604,800 (7 days) for V4 signatures
options...Option(Optional) Additional options such as oss.VersionId or oss.ContentType

For the full API reference, see SignURL.

Download using the signed URL

Share the signed URL with any user. They can download the object using any HTTP client — no OSS credentials required.

All examples below use the same signed URL format. Replace the example URL with the one generated by your Go code.

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

<details> <summary>Java example</summary>

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 signed URL generated by your Go code.
        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******************************************************";
        // Replace with the local path where you want to save the object.
        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");

        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();
        } else {
            System.out.println("No file to download. Server replied HTTP code: " + responseCode);
        }
        httpConn.disconnect();
    }
}

</details>

Node.js

<details> <summary>Node.js example</summary>

const https = require('https');
const fs = require('fs');

// Replace with the signed URL generated by your Go code.
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******************************************************";
// Replace with the local path where you want to save the object.
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);
});

</details>

Python

<details> <summary>Python example</summary>

import requests

# Replace with the signed URL generated by your Go code.
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******************************************************"
# Replace with the local path where you want to save the object.
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)

</details>

Go

<details> <summary>Go example</summary>

package main

import (
    "io"
    "net/http"
    "os"
)

func main() {
    // Replace with the signed URL generated by your Go code.
    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******************************************************"
    // Replace with the local path where you want to save the object.
    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)
    }
}

</details>

JavaScript

<details> <summary>JavaScript example</summary>

// Replace with the signed URL generated by your Go code.
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";

fetch(fileURL)
    .then(response => {
        if (!response.ok) {
            throw new Error(`Server replied HTTP code: ${response.status}`);
        }
        return response.blob();
    })
    .then(blob => {
        const link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = savePath;
        document.body.appendChild(link);
        link.click();
        link.remove();
        console.log("Download completed!");
    })
    .catch(error => {
        console.error("Error during download:", error);
    });

</details>

Android (Java)

<details> <summary>Android (Java) example</summary>

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];
        // Saves the object to the device's Downloads directory.
        String savePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/myfile.txt";
        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();
        }
    }
}

</details>

Objective-C

<details> <summary>Objective-C example</summary>

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // Replace with the signed URL generated by your Go code.
        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******************************************************";
        // Replace your_username with your macOS username.
        NSString *savePath = @"/Users/your_username/Desktop/myfile.txt";

        NSURL *url = [NSURL URLWithString:fileURL];

        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (error) {
                NSLog(@"Error during download: %@", error.localizedDescription);
                return;
            }
            if (!data) {
                NSLog(@"No data received.");
                return;
            }
            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);
            }
        }];

        [task resume];
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

</details>

Other scenarios

Download a specific object version

To download a specific version of an object, pass oss.VersionId as an option when calling SignURL. The generated URL lets the recipient download that exact version.

package main

import (
	"log"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		log.Printf("Error: %v", err)
	}

	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("cn-hangzhou"))
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
	client, err := oss.New("yourEndpoint", "", "", clientOptions...)
	if err != nil {
		log.Printf("Error: %v", err)
	}

	bucketName := "examplebucket"
	// Replace with the full object path (excluding the bucket name).
	objectName := "exampledir/exampleobject.txt"

	bucket, err := client.Bucket(bucketName)
	if err != nil {
		log.Printf("Error: %v", err)
	}

	// Replace with the version ID of the object to download.
	options := []oss.Option{
		oss.VersionId("CAEQEhiBgIDmgPf8mxgiIDA1YjZlNDIxY2ZmMzQ1MmU5MTM1Y2M4Yzk4******"),
	}

	// Generate a signed URL valid for 600 seconds (10 minutes).
	signedURL, err := bucket.SignURL(objectName, oss.HTTPGet, 600, options...)
	if err != nil {
		log.Printf("Error: %v", err)
	}
	log.Printf("Signed URL: %s\n", signedURL)
}

Download an object with a required request header

If you include a request header (such as Content-Type) when generating a signed URL, the downloader must send the same header in their GET request. Omitting the header causes a signature mismatch error.

Step 1: Generate the signed URL with the request header

package main

import (
	"log"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		log.Printf("Error: %v", err)
	}

	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("cn-hangzhou"))
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
	client, err := oss.New("yourEndpoint", "", "", clientOptions...)
	if err != nil {
		log.Printf("Error: %v", err)
	}

	bucketName := "examplebucket"
	objectName := "exampledir/exampleobject.txt"

	bucket, err := client.Bucket(bucketName)
	if err != nil {
		log.Printf("Error: %v", err)
	}

	// Bind Content-Type to the signed URL.
	// The downloader must include this exact Content-Type header in their GET request.
	options := []oss.Option{
		oss.ContentType("text/plain; charset=utf8"),
	}

	signedURL, err := bucket.SignURL(objectName, oss.HTTPGet, 600, options...)
	if err != nil {
		log.Printf("Error: %v", err)
	}
	log.Printf("Signed URL: %s\n", signedURL)
}

Step 2: Download the object with the matching request header

curl

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 "Content-Type: text/plain; charset=utf8" \
  -o "myfile.txt"

Go

package main

import (
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	// Replace with the signed URL generated in Step 1.
	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=LTAI5************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a939feb8d79a389572719f7e2939939936d0**********"

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		log.Fatalf("Failed to create GET request: %v", err)
	}

	// Must match the Content-Type used when generating the signed URL.
	req.Header.Set("Content-Type", "text/plain")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("Failed to send request: %v", err)
	}
	defer resp.Body.Close()

	filePath := "downloadfile.txt"
	file, err := os.Create(filePath)
	if err != nil {
		log.Fatalf("Failed to create local file: %v", err)
	}
	defer file.Close()

	n, err := io.Copy(file, resp.Body)
	if err != nil {
		log.Fatalf("Failed to write object to file: %v", err)
	}

	log.Printf("Wrote %d bytes to %s\n", n, filePath)
}

What's next