阿里云助力您在中国加快取得成功
一站式安全合规咨询服务
MLPS 2.0 一站式合规解决方案
依托我们的网络进军中国市场
提升面向互联网应用的性能和安全性
保障您的中国业务安全无忧
通过强大的数据安全框架保护您的数据资产
申请 ICP 备案的流程解读和咨询服务
面向大数据建设、管理及应用的全域解决方案
企业内大数据建设、管理和应用的一站式解决方案
将您的采购和销售置于同一企业级全渠道数字平台上
全渠道内置 AI 驱动、拟人化、多语言对话的聊天机器人
快速搭建在线教育平台
提供域名注册、分析和保护服务
云原生 Kubernetes 容器化应用运行环境
以 Kubernetes 为使用界面的容器服务产品,提供符合容器规范的算力资源
安全的镜像托管服务,支持全生命周期管理
多集群环境下微服务应用流量统一管理
提供任意基础设施上容器集群的统一管控,助您轻松管控分布式云场景
高弹性、高可靠的企业级无服务器 Kubernetes 容器产品
敏捷安全的 Serverless 容器运行服务
为虚拟机和容器提供高可靠性、高性能、低时延的块存储服务
一款海量、安全、低成本、高可靠的云存储服务
可靠、弹性、高性能、多共享的文件存储服务
全托管、可扩展的并行文件系统服务。
全托管的 NoSQL 结构化数据实时存储服务
可抵扣多种存储产品的容量包,兼具灵活性和长期成本优化
让您的应用跨不同可用区资源自动分配访问量
随时绑定和解绑 VPC ECS
云网络公网、跨域流量统一计费
高性价比,可抵扣按流量计费的流量费用
创建云上隔离的网络,在专有环境中运行资源
在 VPC 环境下构建公网流量的出入口
具备网络状态可视化、故障智能诊断能力的自助式网络运维服务。
安全便捷的云上服务专属连接
基于阿里云专有网络的私有 DNS 解析服务
保障在线业务不受大流量 DDoS 攻击影响
系统运维和安全审计管控平台
业务上云的第一个网络安全基础设施
集零信任内网访问、办公数据保护、终端管理等多功能于一体的办公安全管控平台
提供7X24小时安全运维平台
防御常见 Web 攻击,缓解 HTTP 泛洪攻击
实现全站 HTTPS,呈现可信的 WEB 访问
为云上应用提供符合行业标准和密码算法等级的数据加解密、签名验签和数据认证能力
一款发现、分类和保护敏感数据的安全服务
创建、控制和管理您的加密密钥
快速提高应用高可用能力服务
围绕应用和微服务的 PaaS 平台
兼容主流开源微服务生态的一站式平台
多集群环境下微服务应用流量统一管理
企业级全托管实时数据流平台
全托管,开箱即用的Apache Kafka全托管服务
提供物联网移动端和云交互的消息队列
开箱即用的全托管 RabbitMQ 服务
提供基于消息的可靠异步通信机制
应用之间的消息队列和通知
无服务器事件总线服务
Super MySQL 和 PostgreSQL,高度兼容 Oracle 语法
全托管 MySQL、PostgreSQL、SQL Server、MariaDB
兼容 Redis® 的缓存和KV数据库
兼容Apache Cassandra、Apache HBase、Elasticsearch、OpenTSDB 等多种开源接口
文档型数据库,支持副本集和分片架构
100%兼容 Apache HBase 并深度扩展,稳定、易用、低成本的NoSQL数据库。
低成本、高可用、可弹性伸缩的在线时序数据库服务
专为搜索和分析而设计,成本效益达到开源的两倍,采用最新的企业级AI搜索和AI助手功能。
一款兼容PostgreSQL协议的实时交互式分析产品
一种快速、完全托管的 TB/PB 级数据仓库
基于 Flink 为大数据行业提供解决方案
基于Qwen和其他热门模型的一站式生成式AI平台,可构建了解您业务的智能应用程
一站式机器学习平台,满足数据挖掘分析需求
高性能向量检索服务,提供低代码API和高成本效益
帮助您的应用快速构建高质量的个性化推荐服务能力
提供定制化的高品质机器翻译服务
全面的AI计算平台,满足大模型训练等高性能AI计算的算力和性能需求
具备智能会话能力的会话机器人
基于机器学习的智能图像搜索产品
基于阿里云深度学习技术,为用户提供图像分割、视频分割、文字识别等离线SDK能力,支持Android、iOS不同的适用终端。
语音识别、语音合成服务以及自学习平台
一站式智能搜索业务开发平台
助力金融企业快速搭建超低时延、高质量、稳定的行情数据服务
帮助企业快速测算和分析企业的碳排放和产品碳足迹
企业工作流程自动化,全面提高效率
金融级云原生分布式架构的一站式高可用应用研发、运维平台
eKYC 数字远程在线解决方案
可智能检测、大数据驱动的综合性反洗钱 (AML) 解决方案
阿里云APM类监控产品
实时云监控服务,确保应用及服务器平稳运行
为系统运维人员管理云基础架构提供全方位服务的云上自动化运维平台
面向您的云资源的风险检测服务
提升分布式环境下的诊断效率
日志类数据一站式服务,无需开发就能部署
ECS 预留实例
让弹性计算产品的成本和灵活性达到最佳平衡的付费方式。云原生 AI 套件
加速AI平台构建,提高资源效率和交付速度FinOps
实时分析您的云消耗并实现节约SecOps
实施细粒度安全控制DevOps
快速、安全地最大限度提高您的DevOps优势自带IP上云
自带公网 IP 地址上云全球网络互联
端到端的软件定义网络解决方案,可推动跨国企业的业务发展全球应用加速
提升面向互联网应用的性能和安全性全球互联网接入
将IDC网关迁移到云端云原生 AI 套件
加速AI平台构建,提高资源效率和交付速度FinOps
实时分析您的云消耗并实现节约SecOps
实施细粒度安全控制DevOps
快速、安全地最大限度提高您的DevOps优势金融科技云数据库解决方案
利用专为金融科技而设的云原生数据库解决方案游戏行业云数据库解决方案
提供多种成熟架构,解决所有数据问题Oracle 数据库迁移
将 Oracle 数据库顺利迁移到云原生数据库数据库迁移
加速迁移您的数据到阿里云阿里云上的数据湖
实时存储、管理和分析各种规模和类型的数据数码信贷
利用大数据和 AI 降低信贷和黑灰产风险面向企业数据技术的大数据咨询服务
帮助企业实现数据现代化并规划其数字化未来人工智能对话服务
全渠道内置 AI 驱动、拟人化、多语言对话的聊天机器人EasyDispatch 现场服务管理
为现场服务调度提供实时AI决策支持在线教育
快速搭建在线教育平台窄带高清 (HD) 转码
带宽成本降低高达 30%广电级大型赛事直播
为全球观众实时直播大型赛事,视频播放流畅不卡顿直播电商
快速轻松地搭建一站式直播购物平台用于供应链规划的Alibaba Dchain
构建和管理敏捷、智能且经济高效的供应链云胸牌
针对赛事运营的创新型凭证数字服务数字门店中的云 POS 解决方案
将所有操作整合到一个云 POS 系统中元宇宙
元宇宙是下一代互联网人工智能 (AI) 加速
利用阿里云 GPU 技术,为 AI 驱动型业务以及 AI 模型训练和推理加速DevOps
快速、安全地最大限度提高您的DevOps优势数据迁移解决方案
加速迁移您的数据到阿里云企业 IT 治理
在阿里云上构建高效可控的云环境基于日志管理的AIOps
登录到带有智能化日志管理解决方案的 AIOps 环境备份与存档
数据备份、数据存档和灾难恢复用阿里云金融服务加快创新
在云端开展业务,提升客户满意度
为全球资本市场提供安全、准确和数字化的客户体验
利用专为金融科技而设的云原生数据库解决方案
利用大数据和 AI 降低信贷和黑灰产风险
建立快速、安全的全球外汇交易平台
新零售时代下,实现传统零售业转型
利用云服务处理流量波动问题,扩展业务运营、降低成本
快速轻松地搭建一站式直播购物平台
面向大数据建设、管理及应用的全域解决方案
全渠道内置 AI 驱动、拟人化、多语言对话的聊天机器人
以数字化媒体旅程为当今的媒体市场准备就绪您的内容
带宽成本降低高达 30%
快速轻松地搭建一站式直播购物平台
为全球观众实时直播大型赛事,视频播放流畅不卡顿
使用阿里云弹性高性能计算 E-HPC 将本地渲染农场连接到云端
构建发现服务,帮助客户找到最合适的内容
保护您的媒体存档安全
通过统一的数据驱动平台提供一致的全生命周期客户服务
在钉钉上打造一个多功能的电信和数字生活平台
在线存储、共享和管理照片与文件
提供全渠道的无缝客户体验
面向中小型企业,为独立软件供应商提供可靠的IT服务
打造最快途径,助力您的新云业务扬帆起航
先进的SD-WAN平台,可实现WAN连接、实时优化并降低WAN成本
通过自动化和流程标准化实现快速事件响应
针对关键网络安全威胁提供集中可见性并进行智能安全分析
提供大容量、可靠且高度安全的企业文件传输
用智能技术数字化体育赛事
基于人工智能的低成本体育广播服务
专业的广播转码及信号分配管理服务
基于云的音视频内容引入、编辑和分发服务
在虚拟场馆中模拟关键运营任务
针对赛事运营的创新型凭证数字服务
智能和交互式赛事指南
轻松管理云端背包单元的绑定直播流
通过数据加强您的营销工作
元宇宙是下一代互联网
利用生成式 AI 加速创新,创造新的业务佳绩
阿里云高性能开源大模型
借助AI轻松解锁和提炼文档中的知识
通过AI驱动的语音转文本服务获取洞察
探索阿里云人工智能和数据智能的所有功能、新优惠和最新产品
该体验中心提供广泛的用例和产品帮助文档,助您开始使用阿里云 AI 产品和浏览您的业务数据。
利用阿里云 GPU 技术,为 AI 驱动型业务以及 AI 模型训练和推理加速
元宇宙是下一代互联网
构建发现服务,帮助客户找到最合适的内容
全渠道内置 AI 驱动、拟人化、多语言对话的聊天机器人
加速迁移您的数据到阿里云
在阿里云上建立一个安全且易扩容的环境,助力高效率且高成本效益的上云旅程
迁移到完全托管的云数据库
将 Oracle 数据库顺利迁移到云原生数据库
自带公网 IP 地址上云
利用阿里云强大的安全工具集,保障业务安全、应用程序安全、数据安全、基础设施安全和帐户安全
保护、备份和还原您的云端数据资产
MLPS 2.0 一站式合规解决方案
快速高效地将您的业务扩展到中国,同时遵守适用的当地法规
实现对 CloudOps、DevOps、SecOps、AIOps 和 FinOps 的高效、安全和透明的管理
构建您的原生云环境并高效管理集群
快速、安全地最大限度提高您的DevOps优势
实施细粒度安全控制
提供运维效率和总体系统安全性
实时分析您的云消耗并实现节约
实时存储、管理和分析各种规模和类型的数据
登录到带有智能化日志管理解决方案的 AIOps 环境
帮助企业实现数据现代化并规划其数字化未来
帮助零售商快速规划数字化之旅
将全球知名的 CRM 平台引入中国
在线存储、共享和管理照片与文件
构建、部署和管理高可用、高可靠、高弹性的应用程序
快速、安全地最大限度提高您的DevOps优势
将您的采购和销售置于同一企业级全渠道数字平台上
企业内大数据建设、管理和应用的一站式解决方案
帮助企业简化 IT 架构、实现商业价值、加速数字化转型的步伐
快速高效地将您的业务扩展到中国,同时遵守适用的当地法规
快速搜集、处理、分析联网设备产生的数据
0.0.201
默认情况下,OSS存储空间中文件的读写权限是私有,仅文件拥有者可以上传。但文件拥有者可以对指定的文件生成具有临时访问权限的预签名URL,以允许他人使用该预签名URL在有效期内上传文件。该功能适用于授权合作伙伴上传合同,用户上传头像等场景。
本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见OSS地域和访问域名。
生成PUT方法的预签名URL时,您必须具有oss:PutObject
权限。具体操作,请参见RAM Policy常见示例。
生成预签名URL过程中,SDK利用本地存储的密钥信息,根据特定算法计算出签名(signature),然后将其附加到URL上,以确保URL的有效性和安全性。这一系列计算和构造URL的操作都是在客户端完成,不涉及网络请求到服务端。因此,生成预签名URL时不需要授予调用者特定权限。但是,为避免第三方用户无法对预签名URL授权的资源执行相关操作,需要确保调用生成预签名URL接口的身份主体被授予对应的权限。
预签名URL在有效期内可多次访问,但多次执行上传操作,会有文件覆盖的风险。超期后,需执行步骤一重新生成预签名URL以继续访问文件。
预签名URL上传不支持上传FormData格式,若需使用FormData上传数据,建议使用OSS表单上传。
使用预签名URL上传文件的过程如下:
通过SDK生成的预签名URL,最大有效时长为7天。若使用STSToken来生成预签名URL,则最大有效时长为43200秒(12小时)。
更多SDK信息,请参见Java使用预签名URL上传文件。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.net.URL;
import java.util.*;
import java.util.Date;
public class GetSignUrl {
public static void main(String[] args) throws Throwable {
// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampleobject.txt";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 创建OSSClient实例。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
URL signedUrl = null;
try {
// 指定生成的预签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
// 生成预签名URL。
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
// 设置过期时间。
request.setExpiration(expiration);
// 通过HTTP PUT请求生成预签名URL。
signedUrl = ossClient.generatePresignedUrl(request);
// 打印预签名URL。
System.out.println("signed url for putObject: " + signedUrl);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
}
}
}
更多SDK信息,请参见Go使用预签名URL上传文件。
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"
)
// 定义全局变量
var (
region string // 存储区域
bucketName string // 存储空间名称
objectName string // 对象名称
)
// init函数用于初始化命令行参数
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() {
// 解析命令行参数
flag.Parse()
// 检查bucket名称是否为空
if len(bucketName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, bucket name required")
}
// 检查region是否为空
if len(region) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, region required")
}
// 检查object名称是否为空
if len(objectName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, object name required")
}
// 加载默认配置并设置凭证提供者和区域
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
// 创建OSS客户端
client := oss.NewClient(cfg)
// 生成PutObject的预签名URL
result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
},
oss.PresignExpires(10*time.Minute),
)
if err != nil {
log.Fatalf("failed to put 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 {
//当返回结果包含签名头时,使用签名URL发送Put请求时,需要设置相应的请求头
log.Printf("signed headers:\n")
for k, v := range result.SignedHeaders {
log.Printf("%v: %v\n", k, v)
}
}
}
更多SDK信息,请参见Python使用预签名URL上传文件。
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# 填写Endpoint对应的Region信息,例如cn-hangzhou。注意,v4签名下,必须填写该参数
region = "cn-hangzhou"
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
# 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
object_name = 'exampledir/exampleobject.txt'
# 生成上传文件的签名URL,有效时间为60秒。
# 生成签名URL时,OSS默认会对Object完整路径中的正斜线(/)进行转义,从而导致生成的签名URL无法直接使用。
# 设置slash_safe为True,OSS不会对Object完整路径中的正斜线(/)进行转义,此时生成的签名URL可以直接使用。
url = bucket.sign_url('PUT', object_name, 60, slash_safe=True)
print('签名URL的地址为:', url)
此处仅列举普通场景,如何生成带图片处理参数的预签名URL、如何生成带versionID的预签名URL,请参见Node.js使用预签名URL上传。
const OSS = require("ali-oss");
// 定义一个生成签名 URL 的函数
async function generateSignatureUrl(fileName) {
// 获取预签名URL
const client = await new OSS({
accessKeyId: 'yourAccessKeyId',
accessKeySecret: 'yourAccessKeySecret',
bucket: 'examplebucket',
region: 'oss-cn-hangzhou',
authorizationV4: true
});
return await client.signatureUrlV4('PUT', 3600, {
headers: {} // 请根据实际发送的请求头设置此处的请求头
}, fileName);
}
// 调用函数并传入文件名
generateSignatureUrl('yourFileName').then(url => {
console.log('Generated Signature URL:', url);
}).catch(err => {
console.error('Error generating signature URL:', err);
});
此处仅列举普通场景,如何生成带versionID的预签名URL,请参见PHP使用预签名URL上传。
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Http\RequestCore;
use OSS\Http\ResponseCore;
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
$endpoint = "yourEndpoint";
// 填写Bucket名称。
$bucket= "examplebucket";
// 填写不包含Bucket名称在内的Object完整路径。
$object = "exampleobject.txt";
// 指定预签名URL的过期时间为600s(最长可达32400s)。
$timeout = 600;
try {
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
'signatureVersion'=>OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
// 生成预签名URL。
$signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT");
print_r($signedUrl);
} catch (OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
更多SDK信息,请参见Android使用预签名URL上传文件。
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写不包含Bucket名称在内源Object的完整路径,例如exampleobject.txt。
String objectKey = "exampleobject.txt";
// 设置content-type。
String contentType = "application/octet-stream";
String url = null;
try {
// 生成用于上传文件的预签名URL。
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey);
// 设置预签名URL的过期时间为30分钟。
request.setExpiration(30*60);
request.setContentType(contentType);
request.setMethod(HttpMethod.PUT);
url = oss.presignConstrainedObjectURL(request);
Log.d("url", url);
} catch (ClientException e) {
e.printStackTrace();
}
更多SDK信息,请参见C++使用预签名URL上传文件。
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;
int main(void)
{
/* 初始化OSS账号信息。*/
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/ *yourRegion填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn - hangzhou。 * /
std::string Region = "yourRegion";
/* 填写Bucket名称,例如examplebucket。*/
std::string BucketName = "examplebucket";
/* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
std::string PutobjectUrlName = "exampledir/exampleobject.txt";
/* 初始化网络等资源。*/
InitializeSdk();
ClientConfiguration conf;
conf.signatureVersion = SignatureVersionType::V4;
/* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
client.SetRegion(Region);
/* 设置签名有效时长,最大有效时间为32400秒。*/
std::time_t t = std::time(nullptr) + 1200;
/* 生成预签名URL。*/
auto genOutcome = client.GeneratePresignedUrl(BucketName, PutobjectUrlName, t, Http::Put);
if (genOutcome.isSuccess()) {
std::cout << "GeneratePresignedUrl success, Gen url:" << genOutcome.result().c_str() << std::endl;
}
else {
/* 异常处理。*/
std::cout << "GeneratePresignedUrl fail" <<
",code:" << genOutcome.error().Code() <<
",message:" << genOutcome.error().Message() <<
",requestId:" << genOutcome.error().RequestId() << std::endl;
return -1;
}
/* 释放网络等资源。*/
ShutdownSdk();
return 0;
}
更多SDK信息,请参见iOS使用预签名URL上传文件。
// 填写Bucket名称。
NSString *bucketName = @"examplebucket";
// 填写Object名称。
NSString *objectKey = @"exampleobject.txt";
NSURL *file = [NSURL fileURLWithPath:@"<filePath>"];
NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey];
__block NSString *urlString;
// 生成用于上传的预签名URL,并指定预签名URL过期时间为30分钟。
OSSTask *task = [client presignConstrainURLWithBucketName:bucketName
withObjectKey:objectKey
httpMethod:@"PUT"
withExpirationInterval:30 * 60
withParameters:@{}
contentType:contentType
contentMd5:nil];
[task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
if (task.error) {
NSLog(@"presign error: %@", task.error);
} else {
urlString = task.result;
NSLog(@"url: %@", urlString);
}
return nil;
}];
更多SDK信息,请参见.NET使用预签名URL上传。
using Aliyun.OSS;
using Aliyun.OSS.Common;
// 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称,例如examplebucket。
var bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不包含Bucket名称,例如exampledir/exampleobject.txt。
var objectName = "exampledir/exampleobject.txt";
var objectContent = "More than just cloud.";
// 创建OSSClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
// 生成签名URL。
var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put)
{
// 设置签名URL过期时间,默认值为3600秒。
Expiration = DateTime.Now.AddHours(1),
};
var signedUrl = client.GeneratePresignedUri(generatePresignedUriRequest);
}
catch (OssException ex)
{
Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
Console.WriteLine("Failed with error info: {0}", ex.Message);
}
更多SDK信息,请参见C使用预签名URL下载文件。
#include "oss_api.h"
#include "aos_http_io.h"
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
const char *endpoint = "yourEndpoint";
/* 填写Bucket名称,例如examplebucket。*/
const char *bucket_name = "examplebucket";
/* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
const char *object_name = "exampledir/exampleobject.txt";
/* 填写本地文件的完整路径。*/
const char *local_filename = "yourLocalFilename";
void init_options(oss_request_options_t *options)
{
options->config = oss_config_create(options->pool);
/* 用char*类型的字符串初始化aos_string_t类型。*/
aos_str_set(&options->config->endpoint, endpoint);
/* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
/* 是否使用CNAME访问OSS服务。0表示不使用。*/
options->config->is_cname = 0;
/* 设置网络相关参数,例如超时时间等。*/
options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
/* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
exit(1);
}
/* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
aos_pool_t *pool;
/* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
aos_pool_create(&pool, NULL);
/* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
oss_request_options_t *oss_client_options;
/* 在内存池中分配内存给options。*/
oss_client_options = oss_request_options_create(pool);
/* 初始化Client的选项oss_client_options。*/
init_options(oss_client_options);
/* 初始化参数。*/
aos_string_t bucket;
aos_string_t object;
aos_string_t file;
aos_http_request_t *req;
apr_time_t now;
char *url_str;
aos_string_t url;
int64_t expire_time;
int one_hour = 3600;
aos_str_set(&bucket, bucket_name);
aos_str_set(&object, object_name);
aos_str_set(&file, local_filename);
expire_time = now / 1000000 + one_hour;
req = aos_http_request_create(pool);
req->method = HTTP_PUT;
now = apr_time_now();
/* 单位:微秒 */
expire_time = now / 1000000 + one_hour;
/* 生成预签名URL。*/
url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req);
aos_str_set(&url, url_str);
printf("临时上传URL: %s\n", url_str);
/* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
aos_pool_destroy(pool);
/* 释放之前分配的全局资源。*/
aos_http_io_deinitialize();
return 0;
}
curl -X PUT -T /path/to/local/file "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI5************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a939feb8d79a389572719f7e2939939936d0**********"
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.URL;
import java.util.*;
public class SignUrlUpload {
public static void main(String[] args) throws Throwable {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
// 将<signedUrl>替换为授权URL。
URL signedUrl = new URL("<signedUrl>");
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String pathName = "C:\\Users\\demo.txt";
try {
HttpPut put = new HttpPut(signedUrl.toString());
System.out.println(put);
HttpEntity entity = new FileEntity(new File(pathName));
put.setEntity(entity);
httpClient = HttpClients.createDefault();
response = httpClient.execute(put);
System.out.println("返回上传状态码:"+response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){
System.out.println("使用网络库上传成功");
}
System.out.println(response.toString());
} catch (Exception e){
e.printStackTrace();
} finally {
response.close();
httpClient.close();
}
}
}
import requests
def upload_file(signed_url, file_path):
try:
# 打开文件
with open(file_path, 'rb') as file:
# 发送PUT请求上传文件
response = requests.put(signed_url, data=file)
print(f"返回上传状态码:{response.status_code}")
if response.status_code == 200:
print("使用网络库上传成功")
print(response.text)
except Exception as e:
print(f"发生错误:{e}")
if __name__ == "__main__":
# 将<signedUrl>替换为授权URL。
signed_url = "<signedUrl>"
# 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
file_path = "C:\\Users\\demo.txt"
upload_file(signed_url, file_path)
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func uploadFile(signedUrl, filePath string) error {
// 打开文件
file, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("无法打开文件: %w", err)
}
defer file.Close()
// 创建一个新的HTTP客户端
client := &http.Client{}
// 创建一个PUT请求
req, err := http.NewRequest("PUT", signedUrl, file)
if err != nil {
return fmt.Errorf("创建请求失败: %w", err)
}
// 发送请求
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("发送请求失败: %w", err)
}
defer resp.Body.Close()
// 读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取响应失败: %w", err)
}
fmt.Printf("返回上传状态码: %d\n", resp.StatusCode)
if resp.StatusCode == 200 {
fmt.Println("使用网络库上传成功")
}
fmt.Println(string(body))
return nil
}
func main() {
// 将<signedUrl>替换为授权URL。
signedUrl := "<signedUrl>"
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
filePath := "C:\\Users\\demo.txt"
err := uploadFile(signedUrl, filePath)
if err != nil {
fmt.Println("发生错误:", err)
}
}
const fs = require('fs');
const axios = require('axios');
async function uploadFile(signedUrl, filePath) {
try {
// 创建读取流
const fileStream = fs.createReadStream(filePath);
// 发送PUT请求上传文件
const response = await axios.put(signedUrl, fileStream, {
headers: {
'Content-Type': 'application/octet-stream' // 根据实际情况调整Content-Type
}
});
console.log(`返回上传状态码:${response.status}`);
if (response.status === 200) {
console.log('使用网络库上传成功');
}
console.log(response.data);
} catch (error) {
console.error(`发生错误:${error.message}`);
}
}
// 主函数
(async () => {
// 将<signedUrl>替换为授权URL。
const signedUrl = '<signedUrl>';
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
const filePath = 'C:\\Users\\demo.txt';
await uploadFile(signedUrl, filePath);
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload Example</title>
</head>
<body>
<h1>File Upload Example</h1>
<input type="file" id="fileInput" />
<button id="uploadButton">Upload File</button>
<script>
// 请将此替换为实际的预签名 URL
const signedUrl = "<signedUrl>";
document.getElementById('uploadButton').addEventListener('click', async () => {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (file) {
try {
await upload(file, signedUrl);
} catch (error) {
console.error('Error during upload:', error);
alert('Upload failed: ' + error.message);
}
} else {
console.error('Please select a file');
alert('Please select a file to upload.');
}
});
const upload = async (file, presignedUrl) => {
const chunkSize = 1024 * 1024;
let start = 0;
let end = chunkSize;
while (start < file.size) {
const chunk = file.slice(start, end);
const response = await fetch(presignedUrl, {
method: 'PUT',
body: chunk
});
if (!response.ok) {
throw new Error(`Upload failed for chunk, status: ${response.status}`);
}
console.log('Chunk uploaded successfully');
start = end;
end = start + chunkSize;
}
console.log('File uploaded successfully');
};
</script>
</body>
</html>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
void uploadFile(const std::string& signedUrl, const std::string& filePath) {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// 设置URL
curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
// 设置请求方法为PUT
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// 打开文件
FILE *file = fopen(filePath.c_str(), "rb");
if (!file) {
std::cerr << "无法打开文件: " << filePath << std::endl;
return;
}
// 获取文件大小
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
// 设置文件大小
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
// 设置输入文件句柄
curl_easy_setopt(curl, CURLOPT_READDATA, file);
// 执行请求
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() 失败: " << curl_easy_strerror(res) << std::endl;
} else {
long httpCode = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
std::cout << "返回上传状态码: " << httpCode << std::endl;
if (httpCode == 200) {
std::cout << "使用网络库上传成功" << std::endl;
}
}
// 关闭文件
fclose(file);
// 清理
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
int main() {
// 将<signedUrl>替换为授权URL。
std::string signedUrl = "<signedUrl>";
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
std::string filePath = "C:\\Users\\demo.txt";
uploadFile(signedUrl, filePath);
return 0;
}
package com.example.signurlupload;
import android.os.AsyncTask;
import android.util.Log;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class SignUrlUploadActivity {
private static final String TAG = "SignUrlUploadActivity";
public void uploadFile(String signedUrl, String filePath) {
new UploadTask().execute(signedUrl, filePath);
}
private class UploadTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
String signedUrl = params[0];
String filePath = params[1];
HttpURLConnection connection = null;
DataOutputStream dos = null;
FileInputStream fis = null;
try {
URL url = new URL(signedUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/octet-stream");
fis = new FileInputStream(filePath);
dos = new DataOutputStream(connection.getOutputStream());
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
dos.write(buffer, 0, length);
}
dos.flush();
dos.close();
fis.close();
int responseCode = connection.getResponseCode();
Log.d(TAG, "返回上传状态码: " + responseCode);
if (responseCode == 200) {
Log.d(TAG, "使用网络库上传成功");
}
return "上传完成,状态码: " + responseCode;
} catch (IOException e) {
e.printStackTrace();
return "上传失败: " + e.getMessage();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
@Override
protected void onPostExecute(String result) {
Log.d(TAG, result);
}
}
public static void main(String[] args) {
SignUrlUploadActivity activity = new SignUrlUploadActivity();
// 将<signedUrl>替换为授权URL。
String signedUrl = "<signedUrl>";
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String filePath = "C:\\Users\\demo.txt";
activity.uploadFile(signedUrl, filePath);
}
}
// 通过预签名URL上传文件。
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"PUT";
request.allHTTPHeaderFields = @{OSSHttpHeaderContentType: contentType};
NSURLSession * session = [NSURLSession sharedSession];
NSURLSessionTask * sessionTask = [session uploadTaskWithRequest:request
fromFile:file
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"upload error: %@", error);
return;
} else if (((NSHTTPURLResponse*)response).statusCode == 203 ||
((NSHTTPURLResponse*)response).statusCode >= 300) {
NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"upload error: %@", body);
return;
}
NSLog(@"upload success");
}];
[sessionTask resume];
使用预签名URL分片上传文件需要配置分片大小并逐片生成预签名URL,示例代码如下:
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.common.utils.CRC64;
import com.aliyun.oss.model.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.Date;
public class MultipartUrl {
public static void main(String[] args) throws Throwable {
// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampleobject.txt";
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String pathName = "D:\\localpath\\examplefile.txt";
// 指定生成的预签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
long expireTime = 3600*1000L;
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 创建OSSClient实例。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
// 创建InitiateMultipartUploadRequest对象。
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
// 初始化分片。
InitiateMultipartUploadResult upResult = ossClient.initiateMultipartUpload(initRequest);
// 返回uploadId。uploadId是分片上传事件的唯一标识。您可以根据该uploadId发起相关的操作,例如取消分片上传、查询分片上传等。
String uploadId = upResult.getUploadId();
// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
List<PartETag> partETags = new ArrayList<PartETag>();
// 每个分片的大小,用于计算文件有多少个分片。单位为字节。
long partSize = 1 * 100 * 1024L; //100kb。
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
File sampleFile = new File(pathName);
long fileLength = sampleFile.length();
// 如果希望设置为1个分片,可以将分片大小设置为文件大小。
// long fileLength = sampleFile.length();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
// 设置预签名URL的请求头。
Map<String, String> headers = new HashMap<String, String>();
/*// 指定Object的存储类型。
headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
// 指定ContentType。
headers.put(OSSHeaders.CONTENT_TYPE, "text/plain");*/
// 遍历分片获取分片签名,并上传分片。
// 您还可以一次返回所有分片的预签名URL,然后依次上传。此处以返回单个预签名URL,并通过预签名URL上传单个分片为例。
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
/*// 设置md5校验,只支持对单个分片进行md5校验
FileInputStream inStream = new FileInputStream(pathName);
// 跳过已经上传的分片。
inStream.skip(startPos);
BoundedInputStream entity = new BoundedInputStream(inStream, partSize);
String md5 = BinaryUtil.toBase64String(DigestUtils.md5(entity));
headers.put("Content-MD5", md5);*/
String signUrl = getSignUrl(ossClient, bucketName, objectName, HttpMethod.PUT, expireTime, i + 1, uploadId, headers);
// 通过预签名URL上传文件,以HttpClients为例说明。
putObjectWithHttp(signUrl, pathName, startPos, curPartSize, headers);
}
// 假设合并分片时,与上传分片不在同一个系统。此时,您需要先列举分片,然后再合并分片。
// 列举已上传的分片。
ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);
PartListing partListing = ossClient.listParts(listPartsRequest);
// 遍历分片,并填充partETags。
for (PartSummary part : partListing.getParts()) {
PartETag partETag = new PartETag(part.getPartNumber(), part.getETag());
partETags.add(partETag);
}
// 合并分片。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5("aaa".getBytes()));
// 设置禁止覆盖同名文件。
// completeMultipartUploadRequest.addHeader("x-oss-forbid-overwrite", "true");
// 完成分片上传。
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
System.out.println("合并分片成功,上传分片完成。");
// 校验整体上传文件是否完整
CRC64 crc = new CRC64();
InputStream inStream = new FileInputStream(pathName);
byte[] bytes = new byte[1024];
int cnt;
while ((cnt = inStream.read(bytes)) != -1) {
crc.update(bytes, 0, cnt);
}
if(crc.getValue() == completeMultipartUploadResult.getServerCRC()){
System.out.println("上传文件完整");
} else {
System.out.println("上传文件不完整,请做异常处理");
}
}
public static void putObjectWithHttp(String signedUrl, String pathName, long startPos, long partSize, Map<String, String> headers) throws IOException {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
HttpPut put = new HttpPut(signedUrl);
FileInputStream inStream = new FileInputStream(pathName);
// 跳过已经上传的分片。
inStream.skip(startPos);
InputStreamEntity entity = new InputStreamEntity(inStream, partSize);
BufferedHttpEntity byteArrayEntity = new BufferedHttpEntity(entity);
put.setEntity(byteArrayEntity);
// 如果生成预签名URL时设置了header参数,例如用户元数据,存储类型等,则调用预签名URL上传文件时,也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致,会报签名错误。
for(Map.Entry header: headers.entrySet()){
put.addHeader(header.getKey().toString(),header.getValue().toString());
}
// 加入重试,设置为重试3次。这里仅为举例,业务代码根据需要自行设置重试
httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)).build();
response = httpClient.execute(put);
System.out.println("返回上传状态码:"+response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){
System.out.println("使用网络库上传成功");
}
System.out.println(response.toString());
} catch (Exception e){
e.printStackTrace();
} finally {
if(response != null){
response.close();
}
if(httpClient != null){
httpClient.close();
}
}
}
public static String getSignUrl(OSS ossClient, String bucketName, String objectName, HttpMethod method, long expireTime, int partNum, String uploadId, Map<String, String> headers){
// 指定生成的预签名URL过期时间,单位为毫秒。
Date expiration = new Date(new Date().getTime() + expireTime);
// 生成预签名URL。
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, method);
// 设置过期时间。
request.setExpiration(expiration);
// 将请求头加入到request中。
request.setHeaders(headers);
request.addQueryParameter("partNumber", String.valueOf(partNum));
request.addQueryParameter("uploadId", uploadId);
// 通过HTTP Method请求生成预签名URL。
URL signedUrl = ossClient.generatePresignedUrl(request);
// 打印预签名URL。
System.out.println("signed url: " + signedUrl);
return signedUrl.toString();
}
}
package main
import (
"bytes"
"context"
"flag"
"fmt"
"log"
"net/http"
"time"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)
var (
region string // 区域
bucketName string // 存储桶名称
objectName string // 对象名称
length = int64(5000 * 1024) // 文件总长度,单位为字节
partSize = int64(200 * 1024) // 每个分片的大小,单位为字节
partsNum = int(length/partSize + 1) // 分片的数量
data = make([]byte, length) // 模拟的数据,用于上传
)
// 初始化命令行参数
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() {
// 解析命令行参数
flag.Parse()
// 检查必要参数是否已设置
if len(bucketName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, bucket name required")
}
if len(region) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, region required")
}
if len(objectName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, object name required")
}
// 配置 OSS 客户端
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
// 创建 OSS 客户端
client := oss.NewClient(cfg)
// 初始化分片上传
initResult, err := client.InitiateMultipartUpload(context.TODO(), &oss.InitiateMultipartUploadRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
})
if err != nil {
log.Fatalf("failed InitiateMultipartUpload %v", err)
}
// 遍历每个分片,生成签名 URL 并上传分片
for i := 0; i < partsNum; i++ {
start := int64(i) * partSize
end := start + partSize
if end > length {
end = length
}
signedResult, err := client.Presign(context.TODO(), &oss.UploadPartRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
PartNumber: int32(i + 1),
Body: bytes.NewReader(data[start:end]),
UploadId: initResult.UploadId,
}, oss.PresignExpiration(time.Now().Add(1*time.Hour))) // 生成签名 URL,有效期为1小时
if err != nil {
log.Fatalf("failed to generate presigned URL %v", err)
}
fmt.Printf("signed url:%#v\n", signedResult.URL) // 打印生成的签名URL
// 创建HTTP请求并上传分片
req, err := http.NewRequest(signedResult.Method, signedResult.URL, bytes.NewReader(data[start:end]))
if err != nil {
log.Fatalf("failed to create HTTP request %v", err)
}
c := &http.Client{} // 创建HTTP客户端
_, err = c.Do(req)
if err != nil {
log.Fatalf("failed to upload part by signed URL %v", err)
}
}
// 列举已上传的分片
partsResult, err := client.ListParts(context.TODO(), &oss.ListPartsRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
UploadId: initResult.UploadId,
})
if err != nil {
log.Fatalf("failed to list parts %v", err)
}
// 收集已上传的分片信息
var parts []oss.UploadPart
for _, p := range partsResult.Parts {
parts = append(parts, oss.UploadPart{PartNumber: p.PartNumber, ETag: p.ETag})
}
// 完成分片上传
result, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
UploadId: initResult.UploadId,
CompleteMultipartUpload: &oss.CompleteMultipartUpload{
Parts: parts,
},
})
if err != nil {
log.Fatalf("failed to complete multipart upload %v", err)
}
// 打印完成分片上传的结果
log.Printf("complete multipart upload result:%#v\n", result)
}
通过携带Header参数,您可以定义上传策略(如指定文件存储类型或设置文件ACL)。如果在生成预签名URL时指定了请求头,也要确保在使用预签名URL时包含相应的请求头,以免出现不一致,导致请求失败和签名错误。可设置的Header参数,请参见PutObject。您还可以自定义元数据以便文件管理,如何自定义元数据请参见管理文件元数据。
例如,如果生成预签名URL时设置了Content-Type
和x-oss-storage-class
这两个Header参数,则在使用该URL上传时也需要设置Content-Type
和x-oss-storage-class
这两个Header,否则会返回403。
文件拥有者生成PUT方法的预签名URL。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.net.URL;
import java.util.*;
import java.util.Date;
public class GetSignUrl {
public static void main(String[] args) throws Throwable {
// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "zy-test1009";
// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampleobject1.txt";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 创建OSSClient实例。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
// 设置请求头。
Map<String, String> headers = new HashMap<String, String>();
/*// 指定Object的存储类型。
headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
// 指定ContentType。
headers.put(OSSHeaders.CONTENT_TYPE, "text/plain");*/
// 设置用户自定义元数据。
Map<String, String> userMetadata = new HashMap<String, String>();
/*userMetadata.put("key1","value1");
userMetadata.put("key2","value2");*/
URL signedUrl = null;
try {
// 指定生成的预签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
// 生成预签名URL。
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
// 设置过期时间。
request.setExpiration(expiration);
// 将请求头加入到request中。
request.setHeaders(headers);
// 添加用户自定义元数据。
request.setUserMetadata(userMetadata);
// 通过HTTP PUT请求生成预签名URL。
signedUrl = ossClient.generatePresignedUrl(request);
// 打印预签名URL。
System.out.println("signed url for putObject: " + signedUrl);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
}
}
}
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"
)
// 定义全局变量
var (
region string // 存储区域
bucketName string // 存储空间名称
objectName string // 对象名称
)
// init函数用于初始化命令行参数
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() {
// 解析命令行参数
flag.Parse()
// 检查bucket名称是否为空
if len(bucketName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, bucket name required")
}
// 检查region是否为空
if len(region) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, region required")
}
// 检查object名称是否为空
if len(objectName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, object name required")
}
// 加载默认配置并设置凭证提供者和区域
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
// 创建OSS客户端
client := oss.NewClient(cfg)
// 生成PutObject的预签名URL
result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
ContentType: oss.Ptr("text/plain; charset=utf-8"), // 请确保在服务端生成该签名URL时设置的ContentType与在使用URL时设置的ContentType一致
Metadata: map[string]string{"key1": "value1", "key2": "value2"}, // 请确保在服务端生成该签名URL时设置的Metadata与在使用URL时设置的Metadata一致
},
oss.PresignExpires(10*time.Minute),
)
if err != nil {
log.Fatalf("failed to put 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 {
//当返回结果包含签名头时,使用预签名URL发送Put请求时,需要设置相应的请求头
log.Printf("signed headers:\n")
for k, v := range result.SignedHeaders {
log.Printf("%v: %v\n", k, v)
}
}
}
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# 填写Endpoint对应的Region信息,例如cn-hangzhou。注意,v4签名下,必须填写该参数
region = "cn-hangzhou"
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
# 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
object_name = 'exampledir/exampleobject.txt'
# 指定Header。
headers = dict()
# 指定Content-Type。
headers['Content-Type'] = 'text/plain; charset=utf8'
# 指定存储类型。
headers["x-oss-storage-class"] = "Standard"
# 指定元数据
metadata = {'key1': 'value1', 'key2': 'value2'}
# 更新headers,添加元数据前缀
for key, value in metadata.items():
headers[f'x-oss-meta-{key}'] = value
# 生成上传文件的签名URL,有效时间为60秒。
# 生成签名URL时,OSS默认会对Object完整路径中的正斜线(/)进行转义,从而导致生成的签名URL无法直接使用。
# 设置slash_safe为True,OSS不会对Object完整路径中的正斜线(/)进行转义,此时生成的签名URL可以直接使用。
url = bucket.sign_url('PUT', object_name, 60, slash_safe=True, headers=headers)
print('签名URL的地址为:', url)
其他人使用PUT方法的预签名URL上传文件。
curl -X PUT \
-H "Content-Type: text/plain; charset=utf8" \
-H "x-oss-meta-key1: value1" \
-H "x-oss-meta-key2: value2" \
-T "C:\\Users\\demo.txt" \
"https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI5************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a939feb8d79a389572719f7e2939939936d0**********"
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.URL;
import java.util.*;
public class SignUrlUpload {
public static void main(String[] args) throws Throwable {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
// 将<signedUrl>替换为授权URL。
URL signedUrl = new URL("<signedUrl>");
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String pathName = "C:\\Users\\demo.txt";
// 设置请求头,这里的请求头信息需要与生成URL时的信息一致。
Map<String, String> headers = new HashMap<String, String>();
/*// 指定Object的存储类型。
headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
// 指定ContentType。
headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/
// 设置用户自定义元数据,这里的用户自定义元数据需要与生成URL时的信息一致。
Map<String, String> userMetadata = new HashMap<String, String>();
/*userMetadata.put("key1","value1");
userMetadata.put("key2","value2");*/
try {
HttpPut put = new HttpPut(signedUrl.toString());
System.out.println(put);
HttpEntity entity = new FileEntity(new File(pathName));
put.setEntity(entity);
// 如果生成预签名URL时设置了header参数,例如用户元数据,存储类型等,则调用预签名URL上传文件时,也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致,会报签名错误。
for(Map.Entry header: headers.entrySet()){
put.addHeader(header.getKey().toString(),header.getValue().toString());
}
for(Map.Entry meta: userMetadata.entrySet()){
// 如果使用userMeta,sdk内部会为userMeta拼接"x-oss-meta-"前缀。当您使用其他方式生成预签名URL进行上传时,userMeta也需要拼接"x-oss-meta-"前缀。
put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
}
httpClient = HttpClients.createDefault();
response = httpClient.execute(put);
System.out.println("返回上传状态码:"+response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){
System.out.println("使用网络库上传成功");
}
System.out.println(response.toString());
} catch (Exception e){
e.printStackTrace();
} finally {
response.close();
httpClient.close();
}
}
}
import requests
from requests.auth import HTTPBasicAuth
import os
def upload_file(signed_url, file_path, headers=None, metadata=None):
"""
使用预签名的URL上传文件到OSS。
:param signed_url: 预签名的URL。
:param file_path: 要上传的文件的完整路径。
:param headers: 可选,自定义HTTP头部。
:param metadata: 可选,自定义元数据。
:return: None
"""
if not headers:
headers = {}
if not metadata:
metadata = {}
# 更新headers,添加元数据前缀
for key, value in metadata.items():
headers[f'x-oss-meta-{key}'] = value
try:
with open(file_path, 'rb') as file:
response = requests.put(signed_url, data=file, headers=headers)
print(f"返回上传状态码:{response.status_code}")
if response.status_code == 200:
print("使用网络库上传成功")
else:
print("上传失败")
print(response.text)
except Exception as e:
print(f"发生错误:{e}")
if __name__ == "__main__":
# 将<signedUrl>替换为授权URL。
signed_url = "<signedUrl>"
# 填写本地文件的完整路径。如果未指定本地路径,则默认从脚本所在目录中上传文件。
file_path = "C:\\Users\\demo.txt"
# 设置请求头,这里的请求头信息需要与生成URL时的信息一致。
headers = {
"Content-Type": "text/plain; charset=utf8",
"x-oss-storage-class": "Standard"
}
# 设置用户自定义元数据,这里的用户自定义元数据需要与生成URL时的信息一致。
metadata = {
"key1": "value1",
"key2": "value2"
}
upload_file(signed_url, file_path, headers, metadata)
const fs = require('fs');
const axios = require('axios');
async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
try {
// 更新headers,添加元数据前缀
for (const [key, value] of Object.entries(metadata)) {
headers[`x-oss-meta-${key}`] = value;
}
// 读取文件流
const fileStream = fs.createReadStream(filePath);
// 发送PUT请求
const response = await axios.put(signedUrl, fileStream, {
headers: headers
});
console.log(`返回上传状态码:${response.status}`);
if (response.status === 200) {
console.log("使用网络库上传成功");
} else {
console.log("上传失败");
}
console.log(response.data);
} catch (error) {
console.error(`发生错误:${error.message}`);
}
}
// 主函数
(async () => {
// 将<signedUrl>替换为授权URL。
const signedUrl = "<signedUrl>";
// 填写本地文件的完整路径。如果未指定本地路径,则默认从脚本所在目录中上传文件。
const filePath = "C:\\Users\\demo.txt";
// 设置请求头,这里的请求头信息需要与生成URL时的信息一致。
const headers = {
// "Content-Type": "text/txt",
// "x-oss-storage-class": "Standard"
};
// 设置用户自定义元数据,这里的用户自定义元数据需要与生成URL时的信息一致。
const metadata = {
// "key1": "value1",
// "key2": "value2"
};
await uploadFile(signedUrl, filePath, headers, metadata);
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload Example</title>
</head>
<body>
<h1>File Upload Example</h1>
<input type="file" id="fileInput" />
<button id="uploadButton">Upload File</button>
<script>
// 请将此替换为实际的预签名URL
const signedUrl = "<signedUrl>";
// 设置Content-Type、storageClass和metadata
const contentType = 'text/plain';
const storageClass = 'Standard';
const metadata = {
'x-oss-meta-key1': 'value1',
'x-oss-meta-key2': 'value2'
};
document.getElementById('uploadButton').addEventListener('click', async () => {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (file) {
try {
await upload(file, signedUrl);
} catch (error) {
console.error('Error during upload:', error);
alert('Upload failed: ' + error.message);
}
} else {
console.error('Please select a file');
alert('Please select a file to upload.');
}
});
const upload = async (file, presignedUrl) => {
const chunkSize = 1024 * 1024;
let start = 0;
let end = chunkSize;
while (start < file.size) {
const chunk = file.slice(start, end);
const headers = {
'Content-Type': contentType,
'x-oss-storage-class':storageClass,
...metadata
};
const response = await fetch(presignedUrl, {
method: 'PUT',
headers: headers,
body: chunk
});
if (!response.ok) {
throw new Error(`Upload failed for chunk, status: ${response.status}`);
}
console.log('Chunk uploaded successfully');
start = end;
end = start + chunkSize;
}
console.log('File uploaded successfully');
};
</script>
</body>
</html>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <map>
#include <string>
// 回调函数,用于处理HTTP响应
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
size_t totalSize = size * nmemb;
output->append((char*)contents, totalSize);
return totalSize;
}
void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) {
CURL* curl;
CURLcode res;
std::string readBuffer;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// 设置URL
curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
// 设置请求方法为PUT
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// 打开文件
FILE* file = fopen(filePath.c_str(), "rb");
if (!file) {
std::cerr << "无法打开文件: " << filePath << std::endl;
return;
}
// 设置文件大小
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
rewind(file);
// 设置文件读取回调
curl_easy_setopt(curl, CURLOPT_READDATA, file);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
// 设置请求头
struct curl_slist* chunk = nullptr;
for (const auto& header : headers) {
std::string headerStr = header.first + ": " + header.second;
chunk = curl_slist_append(chunk, headerStr.c_str());
}
for (const auto& meta : metadata) {
std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second;
chunk = curl_slist_append(chunk, metaStr.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
// 设置响应处理回调
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
// 执行请求
res = curl_easy_perform(curl);
// 检查响应
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
} else {
long responseCode;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
std::cout << "返回上传状态码: " << responseCode << std::endl;
if (responseCode == 200) {
std::cout << "使用网络库上传成功" << std::endl;
} else {
std::cout << "上传失败" << std::endl;
}
std::cout << readBuffer << std::endl;
}
// 清理
fclose(file);
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
int main() {
// 将<signedUrl>替换为授权URL。
std::string signedUrl = "<signedUrl>";
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
std::string filePath = "C:\\Users\\demo.txt";
// 设置请求头,这里的请求头信息需要与生成URL时的信息一致。
std::map<std::string, std::string> headers = {
// {"Content-Type", "text/txt"},
// {"x-oss-storage-class", "Standard"}
};
// 设置用户自定义元数据,这里的用户自定义元数据需要与生成URL时的信息一致。
std::map<std::string, std::string> metadata = {
// {"key1", "value1"},
// {"key2", "value2"}
};
uploadFile(signedUrl, filePath, headers, metadata);
return 0;
}
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
)
func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error {
// 打开文件
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
// 读取文件内容
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
return err
}
// 创建请求
req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
if err != nil {
return err
}
// 设置请求头
for key, value := range headers {
req.Header.Set(key, value)
}
// 设置用户自定义元数据
for key, value := range metadata {
req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// 处理响应
fmt.Printf("返回上传状态码:%d\n", resp.StatusCode)
if resp.StatusCode == 200 {
fmt.Println("使用网络库上传成功")
} else {
fmt.Println("上传失败")
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
return nil
}
func main() {
// 将<signedUrl>替换为授权URL。
signedUrl := "<signedUrl>"
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
filePath := "C:\\Users\\demo.txt"
// 设置请求头,这里的请求头信息需要与生成URL时的信息一致。
headers := map[string]string{
// "Content-Type": "text/txt",
// "x-oss-storage-class": "Standard",
}
// 设置用户自定义元数据,这里的用户自定义元数据需要与生成URL时的信息一致。
metadata := map[string]string{
// "key1": "value1",
// "key2": "value2",
}
err := uploadFile(signedUrl, filePath, headers, metadata)
if err != nil {
fmt.Printf("发生错误:%v\n", err)
}
}
import android.os.AsyncTask;
import android.util.Log;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class SignUrlUploadActivity extends AppCompatActivity {
private static final String TAG = "SignUrlUploadActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 将<signedUrl>替换为授权URL。
String signedUrl = "<signedUrl>";
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String pathName = "/storage/emulated/0/demo.txt";
// 设置请求头,这里的请求头信息需要与生成URL时的信息一致。
Map<String, String> headers = new HashMap<>();
// headers.put("Content-Type", "text/txt");
// headers.put("x-oss-storage-class", "Standard");
// 设置用户自定义元数据,这里的用户自定义元数据需要与生成URL时的信息一致。
Map<String, String> userMetadata = new HashMap<>();
// userMetadata.put("key1", "value1");
// userMetadata.put("key2", "value2");
new UploadTask().execute(signedUrl, pathName, headers, userMetadata);
}
private class UploadTask extends AsyncTask<Object, Void, Integer> {
@Override
protected Integer doInBackground(Object... params) {
String signedUrl = (String) params[0];
String pathName = (String) params[1];
Map<String, String> headers = (Map<String, String>) params[2];
Map<String, String> userMetadata = (Map<String, String>) params[3];
try {
URL url = new URL(signedUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setUseCaches(false);
// 设置请求头
for (Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
// 设置用户自定义元数据
for (Entry<String, String> meta : userMetadata.entrySet()) {
connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
}
// 读取文件
File file = new File(pathName);
FileInputStream fileInputStream = new FileInputStream(file);
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
byte[] buffer = new byte[1024];
int count;
while ((count = fileInputStream.read(buffer)) != -1) {
dos.write(buffer, 0, count);
}
fileInputStream.close();
dos.flush();
dos.close();
// 获取响应
int responseCode = connection.getResponseCode();
Log.d(TAG, "返回上传状态码:" + responseCode);
if (responseCode == 200) {
Log.d(TAG, "使用网络库上传成功");
} else {
Log.d(TAG, "上传失败");
}
InputStream is = connection.getInputStream();
byte[] responseBuffer = new byte[1024];
StringBuilder responseStringBuilder = new StringBuilder();
while ((count = is.read(responseBuffer)) != -1) {
responseStringBuilder.append(new String(responseBuffer, 0, count));
}
Log.d(TAG, responseStringBuilder.toString());
return responseCode;
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
@Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
if (result == 200) {
Toast.makeText(SignUrlUploadActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignUrlUploadActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
}
}
}
}
预签名URL是一种安全链接,通过加密签名和有效期验证,临时授权访问特定的OSS文件。生成预签名URL时,本地基于AK/SK密钥对资源路径、过期时间等参数进行加密计算,生成签名参数并将其添加到URL中,形成完整的预签名URL。其典型格式为:https://BucketName.Endpoint/Object?签名参数
。
当第三方访问该URL时,OSS会校验签名参数,若参数被篡改或过期则拒绝访问。
以下为预签名URL示例。
https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-process=image%2Fresize%2Cp_10&x-oss-date=20241115T095058Z&x-oss-expires=3600&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI***********1Uuu%2F20241115%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=6e7*************************1eb79d96
通过这种方式,文件拥有者可以安全地授权第三方访问文件,而无需暴露密钥。
适用场景
短期文件共享:第三方申请上传或下载指定文件,后端便生成带有效期的预签名URL并返回给前端。第三方可以在有效期内使用该URL上传或下载文件,从而保障数据安全。
灵活访问:文件拥有者可以通过邮件或聊天工具等方式分享预签名URL,第三方获取URL后在浏览器地址栏粘贴即可下载文件。
除了预签名URL,阿里云还提供了更灵活的临时授权方式——STS临时访问凭证。如果您希望第三方对OSS的操作不只局限于上传,而是可以执行例如:列举文件、拷贝文件等更多OSS资源的管理操作,建议您了解并使用STS临时访问凭证,详情请参见使用STS临时访问凭证访问OSS。
是的,您可以通过配置Referer防盗链,设置白名单,限制只有通过特定网站(如您的网站)才能访问OSS资源,从而防止其他恶意来源未通过您的网站而直接引用您的OSS文件。详细配置步骤,请参见配置Referer防盗链来阻止其他网站引用OSS文件。
没有配置Bucket跨域策略或跨域策略配置错误,请参考跨域设置进行配置检查。
请求方法不正确。使用签名URL上传文件时,注意使用PUT请求非POST请求。