全部產品
Search
文件中心

Object Storage Service:表單上傳(C# SDK V2)

更新時間:Aug 06, 2025

OSS表單上傳允許網頁應用通過標準HTML表單直接將檔案上傳至OSS。本文介紹如何使用C# SDK V2產生Post簽名和Post Policy等資訊,並調用HTTP Post方法上傳檔案到OSS。

注意事項

  • 本文範例程式碼以華東1(杭州)的地區IDcn-hangzhou為例,預設使用外網Endpoint,如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見OSS地區和訪問網域名稱

  • 通過表單上傳的方式上傳的Object大小不能超過5 GB。

範例程式碼

以下程式碼範例實現了表單上傳的完整過程,主要步驟如下:

  1. 初始化配置與參數:設定地區(region)、儲存桶(bucket)、對象鍵(key)和產品(product),並從環境變數中載入訪問憑證和準備上傳的內容content。

  2. 建立Post Policy:定義上傳請求的有效時間和條件。

  3. 序列化並編碼Policy:將Policy序列化為JSON字串並進行Base64編碼。

  4. 產生簽名密鑰:使用HMAC-SHA256演算法,基於AccessKeySecret產生初始密鑰,再依次對日期、地區、產品和請求類型進行雜湊計算,產生最終的簽名密鑰。

  5. 構建請求體:建立符合HTTP POST規範的Multipart表單資料,添加對象鍵、Base64編碼的Policy、簽名版本、憑證資訊、請求日期、簽名和要上傳的資料。

  6. 建立並執行請求:建立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