Por padrão, os objetos em um bucket do Object Storage Service (OSS) são privados e apenas o proprietário pode acessá-los. Este tópico descreve como usar o OSS PHP SDK para gerar uma URL assinada para uma solicitação GET. Essa URL tem validade temporária e permite que outros usuários baixem o objeto durante um período especificado. É possível acessar a URL várias vezes antes da expiração. Após esse prazo, gere uma nova URL.
Observações
O código de exemplo deste tópico usa o ID da região China (Hangzhou),
cn-hangzhou, como referência. Por padrão, ele usa um endpoint público. Para acessar o OSS a partir de outros serviços da Alibaba Cloud na mesma região, use um endpoint interno. Para mais detalhes sobre as regiões e endpoints compatíveis com o OSS, consulte Regions and endpoints.Este tópico demonstra o uso de variáveis de ambiente para obter credenciais de acesso. Para ver outros exemplos de configuração de credenciais, consulte Configure access credentials for PHP.
Não são necessárias permissões especiais para gerar uma URL assinada. No entanto, terceiros só conseguirão baixar o objeto com sucesso se você possuir a permissão
oss:GetObject. Para saber mais sobre como conceder permissões, consulte Grant custom access policies to a RAM user.Os exemplos de código apresentados aqui usam uma URL assinada V4, cuja validade máxima é de 7 dias. Para mais informações, consulte Signature V4 (recommended).
Procedimento
O procedimento a seguir descreve como baixe um objeto usando uma URL pré-assinada:
Parâmetros
|
Parâmetro |
Obrigatório |
Descrição |
Exemplo |
|
|
Sim |
Região onde o bucket está localizado. |
|
|
|
Sim |
Nome do bucket. |
|
|
|
Sim |
Nome do objeto, incluindo o caminho. |
|
|
|
Não |
Tempo de expiração em segundos. Padrão: 900. |
|
|
|
Não |
Endpoint de acesso. Se não for especificado, o sistema usará automaticamente o endpoint público correspondente à região. |
|
Código de exemplo
-
O proprietário do objeto gera uma URL assinada para uma solicitação GET.
<?php // Import the autoloader file to ensure that dependency libraries are loaded correctly. require_once __DIR__ . '/../../vendor/autoload.php'; use AlibabaCloud\Oss\V2 as Oss; // Define the description for command-line arguments. $optsdesc = [ "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // The region where the bucket is located. (Required) "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // The endpoint to access OSS. (Optional) "bucket" => ['help' => 'The name of the bucket', 'required' => True], // The bucket name. (Required) "key" => ['help' => 'The name of the object', 'required' => True], // The object name. (Required) "expire" => ['help' => 'The expiration time in seconds (default: 900)', 'required' => False], // The expiration time in seconds. (Optional, default: 900) ]; // Convert the argument descriptions to the long options format required by getopt. // A colon ":" after each argument indicates that it requires a value. $longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc)); // Parse the command-line arguments. $options = getopt("", $longopts); // Check if all required arguments are provided. foreach ($optsdesc as $key => $value) { if ($value['required'] === True && empty($options[$key])) { $help = $value['help']; // Get the help information for the argument. echo "Error: the following arguments are required: --$key, $help" . PHP_EOL; exit(1); // If a required argument is missing, exit the program. } } // Extract values from the parsed arguments. $region = $options["region"]; // The region where the bucket is located. $bucket = $options["bucket"]; // The bucket name. $key = $options["key"]; // The object name. $expire = isset($options["expire"]) ? (int)$options["expire"] : 900; // The expiration time. Default: 900 seconds. // Load the credentials from environment variables. // Use EnvironmentVariableCredentialsProvider to read the Access Key ID and Access Key Secret from environment variables. $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider(); // Use the default configurations of the SDK. $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider($credentialsProvider); // Set the credential provider. $cfg->setRegion($region); // Set the region where the bucket is located. if (isset($options["endpoint"])) { $cfg->setEndpoint($options["endpoint"]); // If an endpoint is provided, set it. } try { // Create an OSS client instance. $client = new Oss\Client($cfg); // Create a GetObjectRequest object to download the object. $request = new Oss\Models\GetObjectRequest(bucket:$bucket, key:$key); // Call the presign method to generate a signed URL and set the expiration time. $result = $client->presign($request, [ 'expires' => new \DateInterval("PT{$expire}S") // PT stands for Period Time, and S stands for seconds. ]); // Output the signed URL. echo "Signed URL: " . $result->url . PHP_EOL; } catch (Exception $e) { echo "Error: " . $e->getMessage() . PHP_EOL; exit(1); } -
Outros usuários baixam o objeto usando a URL assinada para a solicitação 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 assinada para solicitação GET visando baixe uma versão específica de um objeto
Baixe um objeto com um cabeçalho de solicitação específico usando uma URL assinada
Gerar uma URL assinada para download usando um nome de domínio personalizado
Referências
Para acessar o código de exemplo completo sobre geração de URLs assinadas, consulte o exemplo no GitHub.
Para obter mais detalhes sobre a operação de API Presign, consulte Presign.