Por padrão, a lista de controle de acesso (ACL) de um objeto em um bucket do Object Storage Service (OSS) é privada. Somente o proprietário do objeto tem permissão para acessá-lo. Este tópico descreve como usar o OSS SDK for Go para gerar uma URL pré-assinada que permite a um usuário baixar temporariamente o objeto por meio de uma solicitação HTTP GET. A URL permanece válida por um período especificado, durante o qual o usuário pode baixar o objeto várias vezes. Após a expiração da URL, é necessário obter uma nova URL pré-assinada.
Observações
O código de exemplo neste tópico utiliza o ID da região
cn-hangzhoureferente à região China (Hangzhou). Por padrão, um endpoint público é utilizado para acessar os recursos do bucket. Caso você acesse esses recursos a partir de outros serviços da Alibaba Cloud na mesma região, utilize um endpoint interno. Para mais informações sobre regiões e endpoints do OSS, consulte Regiões e endpoints.Neste tópico, as credenciais de acesso são obtidas a partir de variáveis de ambiente. Para saber mais sobre como configurar credenciais de acesso, consulte Configurar credenciais de acesso.
Não são necessárias permissões para gerar uma URL pré-assinada. No entanto, para que terceiros possam baixar o objeto utilizando essa URL, o usuário que a gera deve possuir a permissão
oss:GetObject. Para mais detalhes sobre como conceder permissões, consulte Conceder permissões personalizadas a um usuário RAM.Este tópico utiliza URLs pré-assinadas V4, que possuem um período máximo de validade de sete dias. Para mais informações, consulte (Recomendado) Incluir uma assinatura V4 em uma URL.
Procedimento
O procedimento a seguir descreve como baixar um objeto utilizando uma URL pré-assinada:
Definição do método
É possível chamar uma operação específica para gerar uma URL pré-assinada que concede permissões temporárias de acesso aos objetos de um bucket. Essa URL pode ser utilizada múltiplas vezes antes de expirar.
O código abaixo apresenta a sintaxe da operação presign:
func (c *Client) Presign(ctx context.Context, request any, optFns ...func(*PresignOptions)) (result *PresignResult, err error)
Parâmetros da solicitação
|
Parâmetro |
Tipo |
Descrição |
|
ctx |
context.Context |
O contexto da solicitação. |
|
request |
*GetObjectRequest |
Nome da operação da API usada para gerar a URL pré-assinada. |
|
optFns |
...func(*PresignOptions) |
Período de validade da URL pré-assinada. Se este parâmetro não for especificado, a URL adotará o valor padrão de 15 minutos. Este parâmetro é opcional. |
A tabela a seguir detalha as opções disponíveis em PresignOptions.
|
Opção |
Tipo |
Descrição |
|
Expires |
time.Duration |
Defina o período de validade da URL pré-assinada. Por exemplo, para definir uma validade de 30 minutos, configure Expires como 30 * time.Minute. |
|
Expiration |
time.Time |
Indica o horário absoluto de expiração da URL pré-assinada. |
Ao utilizar o algoritmo de assinatura V4, a validade máxima é de sete dias. Caso tanto Expiration quanto Expires sejam especificados, Expiration terá precedência.
Parâmetros de resposta
|
Propriedade da resposta |
Tipo |
Descrição |
|
result |
*PresignResult |
Resultados retornados, incluindo a URL pré-assinada, o método HTTP, o período de validade e os cabeçalhos de solicitação definidos na requisição. |
|
err |
error |
Status da solicitação. Em caso de falha, o valor de err não será nil. |
A tabela abaixo descreve os parâmetros de resposta de PresignResult.
|
Parâmetro |
Tipo |
Descrição |
|
Method |
string |
Método HTTP correspondente à operação. Por exemplo, o método HTTP da operação GetObject é GET. |
|
URL |
string |
A URL pré-assinada gerada. |
|
Expiration |
time.Time |
Horário de expiração da URL pré-assinada. |
|
SignedHeaders |
map[string]string |
Cabeçalhos de solicitação especificados na requisição. Se o valor do cabeçalho Content-Type for definido, por exemplo, as informações sobre Content-Type serão retornadas. |
Código de exemplo
-
O exemplo de código a seguir demonstra como o proprietário de um objeto pode gerar uma URL pré-assinada que permite solicitações HTTP GET:
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 in which the bucket is located. bucketName string // The name of the bucket. objectName string // The name of the object. ) // The init function is used to initialize 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 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) // Generate a presigned 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 { // If the returned result contains signed headers, you must include the corresponding request headers when you send a GET request using the presigned URL. Otherwise, the request may fail or a signature error may occur. log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } } -
Outros usuários podem baixar o arquivo utilizando a URL pré-assinada para solicitações GET.
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; }
Cenários comuns
Gerar uma URL pré-assinada que permita solicitações HTTP GET para uma versão específica de um objeto
Usar uma URL pré-assinada contendo cabeçalhos de solicitação específicos para baixar um objeto
Usar uma URL pré-assinada para forçar o download de um objeto
Gerar uma URL pré-assinada usando um nome de domínio personalizado
Referências
Para acessar o código de exemplo completo usado para baixar um objeto com uma URL pré-assinada, consulte o exemplo no GitHub.
Para mais informações sobre a operação da API que permite baixar um objeto via URL pré-assinada, consulte Presign.