OSS表单上传允许网页应用通过标准HTML表单直接将文件上传至OSS。本文介绍如何使用C# SDK V2生成Post签名和Post Policy等信息,并调用HTTP Post方法上传文件到OSS。
注意事项
本文示例代码以华东1(杭州)的地域ID
cn-hangzhou
为例,默认使用外网Endpoint,如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见OSS地域和访问域名。通过表单上传的方式上传的Object大小不能超过5 GB。
示例代码
以下代码示例实现了表单上传的完整过程,主要步骤如下:
初始化配置与参数:设置区域(region)、存储桶(bucket)、对象键(key)和产品(product),并从环境变量中加载访问凭证和准备上传的内容content。
创建Post Policy:定义上传请求的有效时间和条件。
序列化并编码Policy:将Policy序列化为JSON字符串并进行Base64编码。
生成签名密钥:使用HMAC-SHA256算法,基于AccessKeySecret生成初始密钥,再依次对日期、区域、产品和请求类型进行哈希计算,生成最终的签名密钥。
构建请求体:创建符合HTTP POST规范的Multipart表单数据,添加对象键、Base64编码的Policy、签名版本、凭证信息、请求日期、签名和要上传的数据。
创建并执行请求:创建HTTP客户端并发送POST请求到OSS服务端点,处理响应结果,输出状态码和响应头信息。
using OSS = AlibabaCloud.OSS.V2; // 为阿里云OSS SDK创建别名,简化后续使用
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
var region = "cn-hangzhou"; // 必须项,设置Bucket所在的区域(Region)。以华东1(杭州)为例,Region填写为cn-hangzhou
var bucket = "you bucket name"; // 必须项,Bucket名称
var key = "your object key"; // 必须项,上传的目标对象名称
var product = "oss"; // 必须项,OSS产品标识
// 将字节数组转换为十六进制字符串
static string ToHexString(byte[] data, bool lowercase)
{
var sb = new StringBuilder();
for (var i = 0; i < data.Length; i++) sb.Append(data[i].ToString(lowercase ? "x2" : "X2"));
return sb.ToString();
}
// 给字符串添加双引号
static string quote(string value)
{
return $"\"{value}\"";
}
// 加载OSS SDK的默认配置,此配置会自动从环境变量中读取凭证信息(如AccessKey)
var cfg = OSS.Configuration.LoadDefault();
// 显式设置使用环境变量获取凭证,用于身份验证(格式:OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET)
var credentialsProvider = new OSS.Credentials.EnvironmentVariableCredentialsProvider();
var credentials = credentialsProvider.GetCredentials();
// 要上传的内容
var content = "hello oss";
// 构建Policy(上传策略)
var utcTime = DateTime.UtcNow;
var date = utcTime.ToUniversalTime().ToString("yyyyMMdd", CultureInfo.InvariantCulture);
var dateTime = utcTime.ToUniversalTime().ToString("yyyyMMdd'T'HHmmss'Z'", CultureInfo.InvariantCulture);
var expiration = utcTime.AddHours(1);// 签名有效期1小时
// 构建凭证信息
var credentialInfo = $"{credentials.AccessKeyId}/{date}/{region}/{product}/aliyun_v4_request";
// 构建Policy JSON
var policyMap = new Dictionary<string, Object>()
{
// 设置策略过期时间
{ "expiration",
expiration.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.000'Z'", CultureInfo.InvariantCulture)
},
// 设置上传条件
{ "conditions", new Object[]{
// 必须上传到指定的Bucket
new Dictionary<string, string>() {{ "bucket", bucket } },
// 指定签名版本
new Dictionary<string, string>() {{ "x-oss-signature-version", "OSS4-HMAC-SHA256" } },
// 指定凭证信息
new Dictionary<string, string>() {{ "x-oss-credential", credentialInfo } },
// 指定请求时间
new Dictionary<string, string>() {{ "x-oss-date", dateTime } },
// 限制上传内容长度范围
new Object[]{"content-length-range", 1, 1024 },
//new Object[]{"eq", "$success_action_status", "201"},
//new Object[]{"starts-with", "$key", "user/eric/"},
//new Object[]{"in", "$content-type", new string[]{"image/jpg", "image/png"}},
//new Object[]{ "not-in", "$cache-control", new string[]{ "no-cache" } },
}
},
};
// 序列化为JSON字符串
var policy = JsonSerializer.Serialize(policyMap);
// 对Policy进行Base64编码
var stringToSign = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy));
// 生成签名密钥
using var kha = new HMACSHA256();
// 初始密钥由AccessKeySecret生成
var ksecret = Encoding.UTF8.GetBytes("aliyun_v4" + credentials.AccessKeySecret);
// 逐级生成签名密钥
kha.Key = ksecret;
var hashDate = kha.ComputeHash(Encoding.UTF8.GetBytes(date));
kha.Key = hashDate;
var hashRegion = kha.ComputeHash(Encoding.UTF8.GetBytes(region));
kha.Key = hashRegion;
var hashProduct = kha.ComputeHash(Encoding.UTF8.GetBytes(product));
kha.Key = hashProduct;
var signingKey = kha.ComputeHash(Encoding.UTF8.GetBytes("aliyun_v4_request"));
// 计算最终签名
kha.Key = signingKey;
var signature = ToHexString(kha.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)), true);
// 构建Multipart表单数据
using var formData = new MultipartFormDataContent();
// 处理boundary引号问题
var boundary = formData.Headers.ContentType!.Parameters.ElementAt(0).Value!;
formData.Headers.ContentType.Parameters.ElementAt(0).Value = boundary.Trim('"');
// 添加表单字段 - 对象键名
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(key)), quote("key"));
// 可以添加元数据
//formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(value)), quote("x-oss-"));
// 添加Policy
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(stringToSign)), quote("policy"));
// 添加签名相关信息
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("OSS4-HMAC-SHA256")), quote("x-oss-signature-version"));
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(credentialInfo)), quote("x-oss-credential"));
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(dateTime)), quote("x-oss-date"));
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(signature)), quote("x-oss-signature"));
// 添加要上传的内容
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(content)), quote("file"));
// 发送POST请求到OSS
using var hc = new HttpClient();
var result = await hc.PostAsync($"http://{bucket}.oss-{region}.aliyuncs.com/", formData);
// 打印上传结果
Console.WriteLine("PostObject done"); // 提示操作完成
Console.WriteLine($"StatusCode: {result.StatusCode}"); // HTTP状态码
Console.WriteLine("Response Headers:"); // 响应头信息
result.Headers.ToList().ForEach(x => Console.WriteLine(x.Key + " : " + String.Join(",", x.Value.ToList()))); // 遍历并打印所有响应头
相关文档
关于表单上传的完整示例,请参见postObject.cs。
该文章对您有帮助吗?