默认情况下,OSS Bucket中的文件是私有的,仅文件拥有者可访问。本文介绍如何使用OSS Python SDK生成带有过期时间的GET方法预签名URL,以允许他人临时下载文件。在有效期内可多次访问,超期后需重新生成。
注意事项
本文示例代码以华东1(杭州)的地域ID
cn-hangzhou
为例,默认使用外网Endpoint,如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见OSS地域和访问域名。预签名URL无需权限即可生成,但仅当您拥有
oss:GetObject
权限时,第三方才能通过该预签名URL成功下载文件。具体授权操作,请参见为RAM用户授权自定义的权限策略。本文示例代码使用V4预签名URL,有效期最大为7天。更多信息,请参见签名版本4(推荐)。
使用过程
使用预签名URL下载文件的过程如下:
方法定义
您可以使用预签名接口生成预签名URL,授予对存储空间中对象的限时访问权限。在过期时间之前,您可以多次使用预签名URL。
预签名URL方法定义如下:
presign(request: GetObjectRequest, **kwargs) → PresignResult
请求参数列表
参数名 | 类型 | 说明 |
参数名 | 类型 | 说明 |
request | GetObjectRequest | 设置需要生成预签名URL的方法名,具体请参见Client.presign |
expires | datetime.timedelta | (可选参数)从当前时间开始,多长时间后预签名URL过期。例如设置一个有效期为30分钟,30 * time.Minute。如果不指定,默认有效期为15分钟 |
expiration | datetime.datetime | (可选参数)指定一个具体的日期和时间,作为预签名URL的有效截止时间 |
在签名版本V4下,有效期最长为7天。同时设置Expiration和Expires时,优先取Expiration。
返回值列表
类型 | 说明 |
类型 | 说明 |
PresignResult | 返回结果,包含预签名URL、HTTP方法、过期时间和参与签名的请求头等,具体请参见PresignResult |
其中,PresignResult返回值列举如下:
参数名 | 类型 | 说明 |
参数名 | 类型 | 说明 |
method | str | HTTP方法,和接口对应,例如GetObject接口,返回GET |
url | str | 预签名URL |
expiration | datetime | 预签名URL的过期时间 |
signed_headers | MutableMapping | 被签名的请求头,例如设置了content_type时,会返回 content_type的信息 |
关于预签名方法的完整定义,请参见presign。
示例代码
文件拥有者生成GET方法的预签名URL。
import argparse import alibabacloud_oss_v2 as oss # 创建一个命令行参数解析器,并描述脚本用途:生成GET方法的预签名URL请求示例 parser = argparse.ArgumentParser(description="presign get object sample") # 添加命令行参数 --region,表示存储空间所在的区域,必需参数 parser.add_argument('--region', help='The region in which the bucket is located.', required=True) # 添加命令行参数 --bucket,表示要获取对象的存储空间名称,必需参数 parser.add_argument('--bucket', help='The name of the bucket.', required=True) # 添加命令行参数 --endpoint,表示其他服务可用来访问OSS的域名,非必需参数 parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS') # 添加命令行参数 --key,表示对象(文件)在OSS中的键名,必需参数 parser.add_argument('--key', help='The name of the object.', required=True) def main(): # 解析命令行提供的参数,获取用户输入的值 args = parser.parse_args() # 从环境变量中加载访问OSS所需的认证信息,用于身份验证 credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() # 使用SDK的默认配置创建配置对象,并设置认证提供者 cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider # 设置配置对象的区域属性,根据用户提供的命令行参数 cfg.region = args.region # 如果提供了自定义endpoint,则更新配置对象中的endpoint属性 if args.endpoint is not None: cfg.endpoint = args.endpoint # 使用上述配置初始化OSS客户端,准备与OSS交互 client = oss.Client(cfg) # 生成预签名的GET请求 pre_result = client.presign( oss.GetObjectRequest( bucket=args.bucket, # 指定存储空间名称 key=args.key, # 指定对象键名 ) ) # 打印预签名请求的方法、过期时间和URL print(f'method: {pre_result.method},' f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},' f' url: {pre_result.url}' ) # 打印预签名请求的已签名头信息 for key, value in pre_result.signed_headers.items(): print(f'signed headers key: {key}, signed headers value: {value}') # 当此脚本被直接执行时,调用main函数开始处理逻辑 if __name__ == "__main__": main() # 脚本入口点,控制程序流程从这里开始
其他人使用GET方法的预签名URL下载文件。
curlJavaNode.jsPythonGoJavaScriptAndroid-JavaObjective-Ccurl -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******************************************************"
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(); } }
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); });
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)
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) } }
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); });
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(); } } }
#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; }
常见使用场景
相关文档
关于使用预签名URL下载的完整示例代码,请参见presigner_get_object.py。
- 本页导读 (1)
- 注意事项
- 使用过程
- 方法定义
- 示例代码
- 常见使用场景
- 生成指定版本的文件的GET方法的预签名URL
- 使用预签名URL下载指定请求头的文件
- 使用预签名URL强制下载指定文件
- 使用自定义域名生成用于下载的预签名URL
- 相关文档