預設情況下,OSS Bucket中的檔案是私人的,僅檔案擁有者可訪問。本文介紹如何使用OSS PHP SDK產生帶有到期時間的GET方法預簽名URL,以允許他人臨時下載檔案。在有效期間內可多次訪問,超期後需重建。
注意事項
本文範例程式碼以華東1(杭州)的地區ID
cn-hangzhou為例,預設使用外網Endpoint,如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見地區和Endpoint。本文以從環境變數讀取存取憑證為例。更多配置訪問憑證的樣本,請參見PHP配置訪問憑證。
預簽名URL無需許可權即可產生,但僅當您擁有
oss:GetObject許可權時,第三方才能通過該預簽名URL成功下載檔案。具體授權操作,請參見為RAM使用者授權自訂的權限原則。本文範例程式碼使用V4預簽名URL,有效期間最大為7天。更多資訊,請參見簽名版本4(推薦)。
使用過程
使用預簽名URL下載檔案的過程如下:
參數說明
參數 | 是否必填 | 說明 | 樣本 |
| 是 | Bucket所在的地區 |
|
| 是 | Bucket名稱 |
|
| 是 | 檔案名稱(含路徑) |
|
| 否 | 到期時間(秒),預設900秒 |
|
| 否 | 訪問網域名稱,預設會根據region自動使用對應的外網Endpoint。 |
|
範例程式碼
檔案擁有者產生GET方法的預簽名URL。
<?php // 引入自動負載檔案,確保依賴庫能夠正確載入 require_once __DIR__ . '/../../vendor/autoload.php'; use AlibabaCloud\Oss\V2 as Oss; // 定義命令列參數的描述資訊 $optsdesc = [ "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // Bucket所在的地區(必填) "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // 訪問網域名稱(可選) "bucket" => ['help' => 'The name of the bucket', 'required' => True], // Bucket名稱(必填) "key" => ['help' => 'The name of the object', 'required' => True], // 對象名稱(必填) "expire" => ['help' => 'The expiration time in seconds (default: 900)', 'required' => False], // 到期時間(可選,預設900秒) ]; // 將參數描述轉換為getopt所需的長選項格式 // 每個參數後面加上":"表示該參數需要值 $longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc)); // 解析命令列參數 $options = getopt("", $longopts); // 驗證必填參數是否存在 foreach ($optsdesc as $key => $value) { if ($value['required'] === True && empty($options[$key])) { $help = $value['help']; // 擷取參數的協助資訊 echo "Error: the following arguments are required: --$key, $help" . PHP_EOL; exit(1); // 如果必填參數缺失,則退出程式 } } // 從解析的參數中提取值 $region = $options["region"]; // Bucket所在的地區 $bucket = $options["bucket"]; // Bucket名稱 $key = $options["key"]; // 對象名稱 $expire = isset($options["expire"]) ? (int)$options["expire"] : 900; // 到期時間,預設900秒 // 載入環境變數中的憑證資訊 // 使用EnvironmentVariableCredentialsProvider從環境變數中讀取Access Key ID和Access Key Secret $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider(); // 使用SDK的預設配置 $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider($credentialsProvider); // 設定憑證提供者 $cfg->setRegion($region); // 設定Bucket所在的地區 if (isset($options["endpoint"])) { $cfg->setEndpoint($options["endpoint"]); // 如果提供了訪問網域名稱,則設定endpoint } try { // 建立OSS用戶端執行個體 $client = new Oss\Client($cfg); // 建立GetObjectRequest對象,用於下載對象 $request = new Oss\Models\GetObjectRequest(bucket:$bucket, key:$key); // 調用presign方法產生預簽名URL,設定到期時間 $result = $client->presign($request, [ 'expires' => new \DateInterval("PT{$expire}S") // PT表示Period Time,S表示秒 ]); // 輸出預簽名URL echo "預簽名URL: " . $result->url . PHP_EOL; } catch (Exception $e) { echo "錯誤: " . $e->getMessage() . PHP_EOL; exit(1); }其他人使用GET方法的預簽名URL下載檔案。
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) { // 替換為產生的GET方法的預簽名URL。 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******************************************************"; // 填寫檔案儲存的目標路徑,包括檔案名稱和副檔名。 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(); } }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"; // 檔案將在下載時使用的檔案名稱 fetch(fileURL) .then(response => { if (!response.ok) { throw new Error(`Server replied HTTP code: ${response.status}`); } return response.blob(); // 將響應轉換為 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); });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"; // 修改後的儲存路徑 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 { // 定義檔案 URL 和儲存路徑(修改為有效路徑) 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"; // 請替換為您的使用者名稱 // 建立 URL 對象 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; }