すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:署名付き URL を使用したオブジェクトのアップロード (C# SDK V2)

最終更新日:Nov 09, 2025

デフォルトでは、OSS バケット内のオブジェクトは非公開です。オブジェクト所有者のみがオブジェクトをアップロードする権限を持っています。OSS C# SDK を使用して、他のユーザーがオブジェクトをアップロードできるようにする署名付き URL を生成できます。署名付き URL を生成するときに、有効期限を指定してアクセス期間を制限できます。署名付き URL は、有効期限が切れるまで複数回使用できます。複数のアップロード操作が実行されると、オブジェクトが上書きされる可能性があります。URL の有効期限が切れると、アップロードに使用できなくなります。この場合、新しい署名付き URL を生成する必要があります。

注意事項

  • このトピックのサンプルコードでは、リージョン ID が cn-hangzhou である中国 (杭州) リージョンを例として使用しています。デフォルトではパブリックエンドポイントが使用されます。OSS と同じリージョンにある他の Alibaba Cloud サービスから OSS にアクセスする場合は、内部エンドポイントを使用してください。OSS がサポートするリージョンとエンドポイントの詳細については、「OSS のリージョンとエンドポイント」をご参照ください。

  • 署名付き URL を生成するために特定の権限は必要ありません。ただし、他のユーザーが署名付き URL を使用してオブジェクトをアップロードできるようにするには、oss:PutObject 権限が必要です。詳細については、「RAM ユーザーにバケット内の複数のディレクトリへのアクセスを許可する」をご参照ください。

プロセス

次の図は、HTTP PUT リクエストを許可する署名付き URL を使用してオブジェクトを OSS にアップロードする方法を示しています。

サンプルコード

  1. オブジェクト所有者が PUT リクエストの署名付き URL を生成します。

    重要

    PUT リクエストの署名付き URL を生成する際にリクエストヘッダーを指定した場合、その署名付き URL を使用して PUT リクエストを開始する際にも同じリクエストヘッダーを含める必要があります。そうしないと、リクエストは失敗し、署名の不一致エラーが報告されます。

    using System.Text;
    using OSS = AlibabaCloud.OSS.V2;  // Alibaba Cloud OSS SDK のエイリアスを作成して、後続の使用を簡素化します。
    
    var region = "cn-hangzhou";  // 必須。バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
    var endpoint = null as string;  // オプション。OSS へのアクセスに使用するエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
    var bucket = "your bucket name";  // 必須。バケット名。
    var key = "your object key";  // 必須。OSS にアップロードされた後のオブジェクトの名前。
    
    // OSS SDK のデフォルト設定を読み込みます。この設定は、環境変数から認証情報 (AccessKey など) を自動的に読み取ります。
    var cfg = OSS.Configuration.LoadDefault();
    // 環境変数を使用して ID 検証用の認証情報を取得するように明示的に設定します。フォーマット: OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET。
    cfg.CredentialsProvider = new OSS.Credentials.EnvironmentVariableCredentialsProvider();
    // 設定でバケットのリージョンを設定します。
    cfg.Region = region;   
    // エンドポイントが指定されている場合、デフォルトのエンドポイントを上書きします。 
    if(endpoint != null) 
    {
        cfg.Endpoint = endpoint;
    } 
    
    // 設定情報を使用して OSS クライアントインスタンスを作成します。
    using var client = new OSS.Client(cfg); 
    // Presign メソッドを呼び出して、署名付き URL を生成します。
    var result = client.Presign(new OSS.Models.PutObjectRequest()
    {
        Bucket = bucket,
        Key = key,
    });
    
    // アップロードするコンテンツ。
    const string content = "hello oss!";
    // HttpClient を使用して、署名付き URL を使用してコンテンツをアップロードします。
    using var hc = new HttpClient();
    var httpResult = await hc.PutAsync(result.Url, new ByteArrayContent(Encoding.UTF8.GetBytes(content)));
    
    Console.WriteLine("PutObject done");  // 操作が完了したことを示すメッセージを出力します。
    Console.WriteLine($"StatusCode: {httpResult.StatusCode}");  // 応答の HTTP ステータスコード。
  2. 他のユーザーは、PUT リクエストの署名付き URL を使用してオブジェクトをアップロードします。

    curl

    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=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"

    Java

    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("Status code:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    Go

    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("Unable to open the local file: %w", err)
    	}
    	defer file.Close()
    
    	// HTTP クライアントを作成します。
    	client := &http.Client{}
    
    	// PUT リクエストを作成します。
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("Failed to create the request: %w", err)
    	}
    
    	// リクエストを送信します。
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("Failed to send the request:: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// 応答を読み取ります。
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("Failed to read the request: %w", err)
    	}
    
    	fmt.Printf("Status code: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("The object is uploaded by using the library.")
    	}
    	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("An error occurred: ", err)
    	}
    }
    

    python

    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"Status code: {response.status_code}")
            if response.status_code == 200:
                print("The object is uploaded by using the library.")
            print(response.text)
     
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # <signedUrl> を生成された署名付き URL に置き換えます。 
        signed_url = "<signedUrl>"
        
        # ローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 
        file_path = "C:\\Users\\demo.txt"
    
        upload_file(signed_url, file_path)
    

    Node.js

    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(`Status code: ${response.status}`);
            if (response.status === 200) {
                console.log("The object is uploaded by using the library.");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // main 関数を指定します。
    (async () => {
        // <signedUrl> を署名付き URL に置き換えます。 
        const signedUrl = '<signedUrl>';
        
        // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    重要

    Browser.js と署名付き URL を使用してオブジェクトをアップロードすると、署名の不一致を示す 403 SignatureNotMatch エラーが発生することがあります。これは通常、署名付き URL の生成時に指定されていなかった Content-Type リクエストヘッダーをブラウザが自動的に含めることが原因です。このエラーを防ぐには、署名付き URL を生成する際に Content-Type ヘッダーが指定されていることを確認してください。

    <!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>
            // <signedUrl> をステップ 1 で生成された署名付き URL に置き換えます。 
            const signedUrl = "<signedUrl>"; 
    
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (!file) {
                    alert('Please select a file to upload.');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('File uploaded successfully!');
                } catch (error) {
                    console.error('Error during upload:', error);
                    alert('Upload failed: ' + error.message);
                }
            });
    
            /**
             * ファイルを OSS にアップロードします。
             * @param {File} file - アップロードされるファイル。
             * @param {string} presignedUrl - 署名付き URL。
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,  // ファイル全体をアップロードします。
                });
    
                if (!response.ok) {
                    throw new Error(`Upload failed, status: ${response.status}`);
                }
    
                console.log('File uploaded successfully');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 
    var filePath = "C:\\Users\\demo.txt";
    // <signedUrl> を署名付き URL に置き換えます。
    var presignedUrl = "<signedUrl>";
    
    // HTTP クライアントとローカルファイルストリームを作成します。
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // PUT リクエストを作成します。
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // リクエストを送信します。
    var response = await httpClient.SendAsync(request);
    
    // 応答を処理します。
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}");
        Console.WriteLine("Response Header:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Upload Failed! Status Code: {response.StatusCode}");
        Console.WriteLine("Response content: " + responseContent);
    }

    C++

    #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 << "Unable to open the file: " << 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() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "Status code: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "The object is uploaded by using the network library." << std::endl;
                }
            }
    
            // ローカルファイルを閉じます。
            fclose(file);
    
            // cURL ハンドルをクリアします。
            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;
    }
    

    Android

    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, "Status code: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "The object is uploaded by using the library.");
                    }
    
                    return "Object uploaded. Status code: " + responseCode;
    
                } catch (IOException e) {
                    e.printStackTrace();
                    return "Upload failed: " + 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 を使用して、指定されたリクエストヘッダーとカスタムメタデータを持つオブジェクトをアップロードする

  1. オブジェクト所有者は、指定されたリクエストヘッダーとカスタムメタデータを持つ PUT リクエストの署名付き URL を生成します。

    using System.Text;
    using OSS = AlibabaCloud.OSS.V2;  // Alibaba Cloud OSS SDK のエイリアスを作成して、後続の使用を簡素化します。
    using System.Globalization;
    using System.Net.Http.Headers;
    
    var region = "cn-hangzhou";  // 必須。バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
    var endpoint = null as string;  // オプション。OSS へのアクセスに使用するエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
    var bucket = "your bucket name";  // 必須。バケット名。
    var key = "your object key";  // 必須。OSS にアップロードされた後のオブジェクトの名前。
    
    // OSS SDK のデフォルト設定を読み込みます。この設定は、環境変数から認証情報 (AccessKey など) を自動的に読み取ります。
    var cfg = OSS.Configuration.LoadDefault();
    // 環境変数を使用して ID 検証用の認証情報を取得するように明示的に設定します。フォーマット: OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET。
    cfg.CredentialsProvider = new OSS.Credentials.EnvironmentVariableCredentialsProvider();
    // 設定でバケットのリージョンを設定します。
    cfg.Region = region;   
    // エンドポイントが指定されている場合、デフォルトのエンドポイントを上書きします。 
    if(endpoint != null) 
    { 
        cfg.Endpoint = endpoint;
    } 
    
    // 設定情報を使用して OSS クライアントインスタンスを作成します。
    using var client = new OSS.Client(cfg); 
    // Presign メソッドを呼び出して、署名付きアップロード URL を取得します。
    var result = client.Presign(new OSS.Models.PutObjectRequest()
        {
            Bucket = bucket,
            Key = key,
            StorageClass = "Standard",         // ストレージクラスを Standard に設定します。
            ContentType = "text/plain; charset=utf8",    // コンテンツタイプを設定します。
            Metadata = new Dictionary<string, string>() {
                { "key1", "value1" },    // カスタムメタデータを追加します。
                { "key2", "value2" }
            }
        }
    );
    
    // HTTP クライアントインスタンスを作成します。
    using var hc = new HttpClient();
    
    // アップロードするコンテンツを準備します。
    var content1 = "hello oss";
    var requestMessage = new HttpRequestMessage(HttpMethod.Put, new Uri(result.Url));
    requestMessage.Content = new ByteArrayContent(Encoding.UTF8.GetBytes(content1));
    
    // 署名付き URL に含まれる HTTP ヘッダーを追加します。
    foreach (var item in result.SignedHeaders!)
    {
        switch (item.Key.ToLower())
        {
            case "content-disposition":
                // コンテンツの配置を設定します。
                requestMessage.Content.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(item.Value);
                break;
            case "content-encoding":
                // コンテンツのエンコーディングを設定します。
                requestMessage.Content.Headers.ContentEncoding.Add(item.Value);
                break;
            case "content-language":
                // コンテンツの言語を設定します。
                requestMessage.Content.Headers.ContentLanguage.Add(item.Value);
                break;
            case "content-type":
                // コンテンツタイプを設定します。
                requestMessage.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(item.Value);
                break;
            case "content-md5":
                // コンテンツの MD5 ハッシュを設定します。
                requestMessage.Content.Headers.ContentMD5 = Convert.FromBase64String(item.Value);
                break;
            case "content-length":
                // コンテンツの長さを設定します。
                requestMessage.Content.Headers.ContentLength = Convert.ToInt64(item.Value);
                break;
            case "expires":
                // コンテンツの有効期限を設定します。
                if (DateTime.TryParse(
                        item.Value,
                        CultureInfo.InvariantCulture,
                        DateTimeStyles.None,
                        out var expires
                    ))
                    requestMessage.Content.Headers.Expires = expires;
                break;
            default:
                // その他の一般的なヘッダー情報を追加します。
                requestMessage.Headers.Add(item.Key, item.Value);
                break;
        }
    }
    // HTTP リクエストを送信し、応答を取得します。
    var httpResult = await hc.SendAsync(requestMessage);
    
    Console.WriteLine("PutObject done");  // 操作が完了したことを示すメッセージを出力します。
    Console.WriteLine($"StatusCode: {httpResult.StatusCode}");  // 応答の HTTP ステータスコード。
  2. 他のユーザーは、PUT リクエストの署名付き URL を使用してオブジェクトをアップロードします。

    curl

    curl -X PUT \
         -H "Content-Type: text/plain;charset=utf8" \
         -H "x-oss-storage-class: Standard" \
         -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=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"

    Java

    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.StorageClass;
    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>();
            // オブジェクトのストレージクラスを指定します。 
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            // コンテンツタイプを指定します。 
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // ユーザーメタデータを指定します。ここでのユーザーメタデータが、署名付き 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 の生成時にユーザーメタデータやストレージクラスなどのヘッダーを設定した場合、署名付き URL を使用してファイルをアップロードする際には、これらのヘッダーをサーバーに送信する必要があります。署名計算のためにサーバーに送信されるヘッダーが、署名付き URL の生成時に指定されたヘッダーと異なる場合、署名エラーが報告されます。 
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
                for(Map.Entry meta: userMetadata.entrySet()){
                    // ユーザーメタデータが指定されている場合、SDK はユーザーメタデータキーに「x-oss-meta-」プレフィックスを追加します。他のメソッドを使用してファイルをアップロードする場合は、「x-oss-meta-」プレフィックスがユーザーメタデータキーにも追加されていることを確認してください。 
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Status code of the upload: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    Go

    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("Status code: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("The object is uploaded by using the library.")
    	} else {
    		fmt.Println("Upload failed")
    	}
    	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/plain;charset=utf8",
    		"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("An error occurred: %v\n", err)
    	}
    }
    

    Python

    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: リクエストヘッダー。 このパラメーターはオプションです。
        :param metadata: ユーザーメタデータ。 このパラメーターはオプションです。
        :return: なし
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # メタデータキーに x-oss-meta- プレフィックスを追加します。
        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"Status code: {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)
    

    Node.js

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // メタデータキーに x-oss-meta- プレフィックスを追加します。
            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(`Status code: ${response.status}`);
            if (response.status === 200) {
                console.log("The object is uploaded by using the library.");
            } else {
                console.log("Upload failed.");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // main 関数を指定します。
    (async () => {
        // <signedUrl> を署名付き URL に置き換えます。 
        const signedUrl = "<signedUrl>";
    
        // ローカルファイルの完全なパスを指定します。デフォルトでは、ローカルファイルの完全なパスを指定しない場合、ローカルファイルはスクリプトが保存されているディレクトリからアップロードされます。 
        const filePath = "C:\\Users\\demo.txt";
    
        // リクエストヘッダーを指定します。リクエストヘッダーの値が、署名付き URL の生成時に指定された値と同じであることを確認してください。 
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // ユーザーメタデータを指定します。ここでのユーザーメタデータが、署名付き URL の生成時に指定されたユーザーメタデータと同じであることを確認してください。 
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    重要

    Browser.js コードを使用して署名付き URL に基づいてオブジェクトをアップロードすると、署名の不一致を示す 403 エラーが発生することがあります。このエラーは、署名付き URL の生成時に指定されていなかった要素である Content-Type リクエストヘッダーをブラウザが自動的に追加するために発生する署名検証の失敗に起因します。このエラーを解決するには、Browser.js コードで OSS にデータをアップロードするために使用されることが想定される署名付き URL を生成する際に、Content-Type ヘッダーを指定する必要があります。

    <!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>
            // <signedUrl> を実際の署名付き 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 {
                    alert('Please select a file to upload.');
                }
            });
    
            const upload = async (file, presignedUrl) => {
                const headers = {
                    "Content-Type": "text/plain;charset=utf8",
                    'x-oss-storage-class': 'Standard',
                    'x-oss-meta-key1': 'value1',
                    'x-oss-meta-key2': 'value2'
                };
    
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    headers: headers,
                    body: file
                });
    
                if (!response.ok) {
                    throw new Error(`Upload failed, status: ${response.status}`);
                }
    
                alert('File uploaded successfully');
                console.log('File uploaded successfully');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // アップロードするローカルファイルの完全なパスを指定します。ローカルファイルのパスが指定されていない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。 
    var filePath = "C:\\Users\\demo.txt";
    // <signedUrl> を署名付き URL に置き換えます。
    var presignedUrl = "<signedUrl>";
    
    // HTTP クライアントとローカルファイルストリームを作成します。
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // PUT リクエストを作成します。
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // 署名付き URL の生成時にユーザーメタデータやストレージクラスなどのヘッダーを設定した場合、署名付き URL を使用してファイルをアップロードする際には、これらのヘッダーをサーバーに送信する必要があります。
    // リクエストヘッダーを指定します。リクエストヘッダーの値が、署名付き URL の生成時に指定された値と同じであることを確認してください。
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "utf8" };  // コンテンツタイプを指定します。      
    // ユーザーメタデータを指定します。ユーザーメタデータが、署名付き URL の生成時に指定されたユーザーメタデータと同じであることを確認してください。
    request.Content.Headers.Add("x-oss-meta-key1", "value1");
    request.Content.Headers.Add("x-oss-meta-key2", "value2");
    // オブジェクトのストレージクラスを指定します。
    request.Content.Headers.Add("x-oss-storage-class", "Standard");
    
    // リクエストヘッダーを出力します。
    Console.WriteLine("Request header:");
    foreach (var header in request.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    
    // リクエストを送信します。
    var response = await httpClient.SendAsync(request);
    
    // 応答を処理します。
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}");
        Console.WriteLine("Response Header:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Upload failed! Status Code: {response.StatusCode}");
        Console.WriteLine("Response Content: " + responseContent);
    }

    C++

    #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 << "Unable to open the file: " << 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 << "Status code: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "The object is uploaded by using the network library." << std::endl;
                } else {
                    std::cout << "Upload failed." << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // cURL ハンドルをクリアします。
            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/plain;charset=utf8"},
             {"x-oss-storage-class", "Standard"}
        };
    
        // ユーザーメタデータを指定します。ここでのユーザーメタデータが、署名付き URL の生成時に指定されたユーザーメタデータと同じであることを確認してください。 
        std::map<std::string, std::string> metadata = {
             {"key1", "value1"},
             {"key2", "value2"}
        };
    
        uploadFile(signedUrl, filePath, headers, metadata);
    
        return 0;
    }
    

    Android

    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/plain;charset=utf8");
            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, "Status code: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "The object is uploaded by using the library.");
                    } else {
                        Log.d(TAG, "Upload failed");
                    }
    
                    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, "Object uploaded", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Upload failed", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

署名付き URL を使用してマルチパートアップロードでオブジェクトをアップロードする

署名付き URL とマルチパートアップロードを使用してオブジェクトをアップロードするには、パートサイズを設定し、各パートの署名付き URL を生成する必要があります。次のサンプルコードに例を示します。

using OSS = AlibabaCloud.OSS.V2;  // Alibaba Cloud OSS SDK のエイリアスを作成して、後続の使用を簡素化します。

var region = "cn-hangzhou";  // 必須。バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
var endpoint = null as string;  // オプション。OSS へのアクセスに使用するエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
var bucket = "you bucket name";  // 必須。バケット名。
var key = "your object key";  // 必須。アップロードするオブジェクトの名前。
var partSize = 512*1024;  // 必須。各アップロードの各パートのサイズ。この例では、パートサイズは 512 KB です。
var filePath = "filePath";  // 必須。アップロードするオブジェクトのパス。

// OSS SDK のデフォルト設定を読み込みます。この設定は、環境変数から認証情報 (AccessKey など) を自動的に読み取ります。
var cfg = OSS.Configuration.LoadDefault();
// 環境変数を使用して ID 検証用の認証情報を取得するように明示的に設定します。フォーマット: OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET。
cfg.CredentialsProvider = new OSS.Credentials.EnvironmentVariableCredentialsProvider();
// 設定でバケットのリージョンを設定します。
cfg.Region = region;   
// エンドポイントが指定されている場合、デフォルトのエンドポイントを上書きします。 
if(endpoint != null) 
{
    cfg.Endpoint = endpoint;
} 

// 設定情報を使用して OSS クライアントインスタンスを作成します。
using var client = new OSS.Client(cfg); 

// マルチパートアップロードを開始します。
var initResult = await client.InitiateMultipartUploadAsync(new()
{
    Bucket = bucket,
    Key = key
});

// アップロードするファイルを開きます。
using var hc = new HttpClient();
using var file = File.OpenRead(filePath);
long fileSize = file.Length;
long partNumber = 1;

// ファイルをパートに分けてアップロードします。
for (long offset = 0; offset < fileSize; offset += partSize)
{
    // 現在のパートのサイズを計算します。
    var size = Math.Min(partSize, fileSize - offset);

    // クライアントから直接アップロードするための署名付き URL を生成します。
    var presignResult = client.Presign(new OSS.Models.UploadPartRequest
    {
        Bucket = bucket,
        Key = key,
        PartNumber = partNumber,
        UploadId = initResult.UploadId,
        Body = new OSS.IO.BoundedStream(file, offset, size)
    });

    // 署名付き URL を使用して PUT リクエストを送信し、パートをアップロードします。
    var httpResult = await hc.PutAsync(
        presignResult.Url,
        new StreamContent(new OSS.IO.BoundedStream(file, offset, size))
    );

    // アップロードが成功したかどうかを確認します。
    if (!httpResult.IsSuccessStatusCode)
    {
        throw new Exception("upload part fail");
    }
    partNumber++;
}

// アップロードされたすべてのパートをリストします。
var uploadParts = new List<OSS.Models.UploadPart>();
var paginator = client.ListPartsPaginator(new ()
{
    Bucket = bucket,
    Key = key,
    UploadId = initResult.UploadId,
});

// すべてのパート情報をページごとに取得します。
await foreach (var page in paginator.IterPageAsync())
{
    foreach (var part in page.Parts ?? [])
    {
        uploadParts.Add(new() { PartNumber = part.PartNumber, ETag = part.ETag });
    }
}

// パートをパート番号で並べ替えます。
uploadParts.Sort((left, right) => { return (left.PartNumber > right.PartNumber) ? 1 : -1; });

// マルチパートアップロードを完了します。
var cmResult = await client.CompleteMultipartUploadAsync(new()
{
    Bucket = bucket,
    Key = key,
    UploadId = initResult.UploadId,
    CompleteMultipartUpload = new()
    {
        Parts = uploadParts
    }
});

// アップロード結果を出力します。
Console.WriteLine("MultipartUpload done");  // 操作が完了したことを示すメッセージ。
Console.WriteLine($"StatusCode: {cmResult.StatusCode}");  // HTTP ステータスコード。
Console.WriteLine($"RequestId: {cmResult.RequestId}");  // リクエスト ID。Alibaba Cloud がトラブルシューティングに使用します。
Console.WriteLine("Response Headers:");  // 応答ヘッダー情報。
cmResult.Headers.ToList().ForEach(x => Console.WriteLine(x.Key + " : " + x.Value));  // すべての応答ヘッダーを走査して出力します。

よくある質問

一時的な署名を使用してオブジェクトをアップロードし、アップロード中に署名の有効期限が切れた場合、アップロードは失敗しますか?

アップロードは成功します。

署名は、アップロードリクエストが開始されたときに検証されます。その時点で URL が有効であれば、アップロードは続行できます。一時的なトークンを使用する場合、署名付き URL の有効期間は、トークンの有効期間と URL の指定された有効期限のいずれか短い方になります。

URL を生成するときにリクエストヘッダーとカスタムメタデータを設定しない場合、アップロードに URL を使用するときにそれらを設定する必要がありますか?

いいえ、必要ありません。

リクエストヘッダーとカスタムメタデータはオプションのパラメーターです。リクエストヘッダーとカスタムメタデータを設定しない場合は、サンプルコードから関連するコードを削除できます。

リファレンス

署名付き URL を使用してオブジェクトをアップロードするために使用される完全なサンプルコードについては、「PresignPutObject.cs」をご参照ください。