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

Object Storage Service:OSS SDK for Python V2 を使用して生成された署名付き URL を使用してオブジェクトをアップロードする

最終更新日:Aug 13, 2025

デフォルトでは、バケット内の Object Storage Service (OSS) オブジェクトのアクセス制御リスト (ACL) は非公開です。オブジェクト所有者のみが、バケットにオブジェクトをアップロードする権限を持っています。 OSS SDK for Python を使用して署名付き URL を生成し、その署名付き URL をユーザーと共有することで、ユーザーがオブジェクトをアップロードできるようにすることができます。署名付き URL を生成する際に、ユーザーがオブジェクトをアップロードできる期間を制限するために、署名付き URL の有効期間を指定できます。署名付き URL の有効期間中は、ユーザーはその URL を使用してバケットにオブジェクトを複数回アップロードできます。オブジェクトを複数回アップロードすると、アップロードされたオブジェクトが上書きされる可能性があります。署名付き URL の有効期間が終了すると、ユーザーはその署名付き URL を使用してオブジェクトをアップロードできなくなります。この場合、新しい署名付き URL を生成する必要があります。

使用上の注意

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

  • 署名付き URL を生成するために特定の権限は必要ありません。ただし、サードパーティが署名付き URL を使用してオブジェクトをアップロードできるようにするには、oss:PutObject 権限が必要です。詳細については、「カスタムポリシーを使用して RAM ユーザーに権限を付与する」をご参照ください。

  • このトピックでは、V4 署名を含み、最大 7 日間の有効期間を持つ署名付き URL を使用します。詳細については、「(推奨) 署名付き URL の V4 署名」をご参照ください。

プロセス

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

メソッド

特定の操作を呼び出して署名付き URL を生成し、その署名付き URL を使用してバケット内のオブジェクトに対する一時的なアクセス権限を付与できます。署名付き URL は、有効期限が切れるまで複数回使用できます。

構文:

presign(request: PutObjectRequest, **kwargs) → PresignResult

リクエストパラメーター

パラメーター

タイプ

説明

request

PutObjectRequest

署名付き URL を生成するために使用される API 操作。詳細については、Client.presign をご参照ください。

expires

datetime.timedelta

署名付き URL の有効期間。これはオプションのパラメーターです。たとえば、有効期間を 30 分に設定するには、expires を 30 * time.Minute に設定します。このパラメーターを指定しない場合、署名付き URL はデフォルト値である 15 分を使用します。

expiration

datetime.datetime

署名付き URL の絶対有効期限。これはオプションのパラメーターです。

重要

V4 署名アルゴリズムを使用する場合、有効期間は最大 7 日間です。Expiration と Expires の両方を指定した場合、Expiration が優先されます。

レスポンスパラメーター

タイプ

説明

PresignResult

署名付き URL、HTTP メソッド、有効期限、リクエストで指定されたリクエストヘッダーを含む、返された結果。詳細については、PresignResult をご参照ください。

PresignResult のレスポンスパラメーター

パラメーター

タイプ

説明

method

str

API 操作に対応する HTTP メソッド。たとえば、PutObject 操作の HTTP メソッドは PUT です。

url

str

署名付き URL。

expiration

datetime

署名付き URL の有効期限。

signed_headers

MutableMapping

リクエストで指定された署名付きヘッダー。たとえば、Content-Type が指定されている場合、Content-Type に関する情報が返されます。

presign メソッドの詳細については、presign をご参照ください。

サンプルコード

  1. HTTP PUT リクエストを許可する署名付き URL を生成します。

    重要

    HTTP PUT リクエストを許可する署名付き URL を生成するときにリクエストヘッダーを指定する場合は、署名付き URL を使用して開始された PUT リクエストにリクエストヘッダーが含まれていることを確認してください。これにより、リクエストの失敗と署名エラーを防ぎます。

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # コマンドラインパラメータパーサーを作成し、スクリプトの目的を記述します。この例では、HTTP PUT リクエストを許可する署名付き URL を生成する方法について説明します。
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # 必須のリージョン、バケット名、エンドポイント、オブジェクト名を含むコマンドラインパラメータを指定します。
    parser.add_argument('--region', help='バケットが配置されているリージョン。', required=True)
    parser.add_argument('--bucket', help='バケットの名前。', required=True)
    parser.add_argument('--endpoint', help='他のサービスが OSS にアクセスするために使用できるドメイン名')
    parser.add_argument('--key', help='オブジェクトの名前。', required=True)
    
    def main():
        # コマンドラインパラメータを解析して、ユーザーが指定した値を取得します。
        args = parser.parse_args()
    
        # 認証のために環境変数からアクセス認証情報を取得します。
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # SDK のデフォルト設定を使用して設定オブジェクトを作成し、認証情報プロバイダーを指定します。
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # ユーザーが指定したコマンドラインパラメータに基づいて、設定オブジェクトのリージョン属性を指定します。
        cfg.region = args.region
    
        # カスタムエンドポイントが提供されている場合は、設定オブジェクトの endpoint パラメータを変更します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # 前述の設定を使用して OSSClient インスタンスを初期化し、インスタンスが OSS と対話できるようにします。
        client = oss.Client(cfg)
    
        # リクエストを送信して PUT リクエストを開始し、指定されたオブジェクトの署名付き URL を生成します。
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket, # バケットの名前。
            key=args.key, # オブジェクトの名前。
        ),expires=timedelta(seconds=3600)) # リクエストの有効期間を指定します。この例では、有効期間は 3,600 秒に設定されています。
    
        # リクエストで指定されたメソッド、有効期限、署名付き URL を表示して、署名付き URL の有効性を確認します。
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # リクエストで署名されたヘッダーを表示します。これらは、リクエストの送信時に HTTP ヘッダーに含まれます。
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # スクリプトが直接実行されたときに main 関数を呼び出して処理ロジックを開始します。
    if __name__ == "__main__":
        main() # スクリプトの関数のエントリポイントを指定します。制御プログラムフローはここから開始されます。
  2. HTTP 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("返されたステータスコード:" + 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();
            }
        }
    }       

    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("ファイルを開けませんでした: %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)
    	}
    }
    

    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"返されたステータスコード: {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)
    

    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(`返されたステータスコード: ${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);
    })();

    browser.js

    重要

    Browser.js を使用してファイルをアップロードし、403 SignatureDoesNotMatch エラーが発生した場合、通常、ブラウザが自動的に Content-Type リクエストヘッダーを追加するためにエラーが発生します。署名付き URL の生成時にこのヘッダーが指定されていない場合、署名の検証は失敗します。この問題を解決するには、署名付き 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>ファイルアップロードの例</title>
    </head>
    <body>
        <h1>ファイルアップロードの例</h1>
    
        <!-- ファイルを選択 -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">ファイルをアップロード</button>
    
        <script>
            // これを手順 1 で生成された署名付き URL に置き換えます。
            const signedUrl = "<signedUrl>"; 
    
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (!file) {
                    alert('アップロードするファイルを選択してください。');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('ファイルが正常にアップロードされました!');
                } catch (error) {
                    console.error('アップロード中にエラーが発生しました:', error);
                    alert('アップロードに失敗しました: ' + 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(`アップロードに失敗しました、ステータス: ${response.status}`);
                }
    
                console.log('ファイルが正常にアップロードされました');
            };
        </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($"正常にアップロードされました! ステータスコード: {response.StatusCode}");
        Console.WriteLine("レスポンスヘッダー:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"アップロードに失敗しました! ステータスコード: {response.StatusCode}");
        Console.WriteLine("レスポンスコンテンツ: " + 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 << "ファイルを開けませんでした: " << 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;
    }
    

    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, "返されたステータスコード: " + 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 を使用してオブジェクトをアップロードする

  1. 特定のリクエストヘッダーとユーザーメタデータを含み、HTTP PUT リクエストを許可する署名付き URL を生成します。

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # コマンドラインパラメータパーサーを作成し、スクリプトの目的を記述します。この例では、HTTP PUT リクエストを許可する署名付き URL を生成する方法について説明します。
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # 必須のリージョン、バケット名、エンドポイント、オブジェクト名を含むコマンドラインパラメータを指定します。
    parser.add_argument('--region', help='バケットが配置されているリージョン。', required=True)
    parser.add_argument('--bucket', help='バケットの名前。', required=True)
    parser.add_argument('--endpoint', help='他のサービスが OSS にアクセスするために使用できるドメイン名')
    parser.add_argument('--key', help='オブジェクトの名前。', required=True)
    
    def main():
        # コマンドラインパラメータを解析して、ユーザーが指定した値を取得します。
        args = parser.parse_args()
    
        # 認証のために環境変数からアクセス認証情報を取得します。
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # SDK のデフォルト設定を使用して設定オブジェクトを作成し、認証情報プロバイダーを指定します。
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # ユーザーが指定したコマンドラインパラメータに基づいて、設定オブジェクトのリージョン属性を指定します。
        cfg.region = args.region
    
        # カスタムエンドポイントが提供されている場合は、設定オブジェクトの endpoint パラメータを変更します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # 前述の設定を使用して OSSClient インスタンスを初期化し、インスタンスが OSS と対話できるようにします。
        client = oss.Client(cfg)
    
        # リクエストを送信して PUT リクエストを開始し、指定されたオブジェクトの署名付き URL を生成します。
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket, # バケットの名前。
            key=args.key, # オブジェクトの名前。
            content_type='text/plain;charset=utf8', # オブジェクトのタイプを指定します。
            storage_class='Standard', # オブジェクトのストレージクラスを指定します。
            metadata={
                'key1': 'value1', # オブジェクトのメタデータを指定します。
                'key2': 'value2' # オブジェクトのメタデータを指定します。
            }
        ),expires=timedelta(seconds=3600)) # リクエストの有効期間を指定します。この例では、有効期間は 3,600 秒に設定されています。
    
    
        # リクエストで指定されたメソッド、有効期限、署名付き URL を表示して、署名付き URL の有効性を確認します。
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # リクエストで署名されたヘッダーを表示します。これらは、リクエストの送信時に HTTP ヘッダーに含まれます。
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # スクリプトが直接実行されたときに main 関数を呼び出して処理ロジックを開始します。
    if __name__ == "__main__":
        main() # スクリプトの関数のエントリポイントを指定します。制御プログラムフローはここから開始されます。
  2. HTTP 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());
            // ContentType を指定します。
            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 を使用してファイルをアップロードするときにサーバーに送信する必要があります。サーバーに送信された署名が生成された署名と異なる場合、署名エラーが報告されます。
                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();
            }
        }
    }       

    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("返されたステータスコード: %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/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("エラーが発生しました: %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: オプション。カスタム HTTP ヘッダー。
        :param metadata: オプション。カスタムメタデータ。
        :return: なし
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # ヘッダーを更新し、メタデータプレフィックスを追加します。
        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)
    

    Node.js

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // ヘッダーを更新し、メタデータプレフィックスを追加します。
            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/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 を使用してファイルをアップロードし、403 SignatureDoesNotMatch エラーが発生した場合、通常、ブラウザが自動的に Content-Type リクエストヘッダーを追加するためにエラーが発生します。署名付き URL の生成時にこのヘッダーが指定されていない場合、署名の検証は失敗します。この問題を解決するには、署名付き 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>ファイルアップロードの例</title>
    </head>
    <body>
        <h1>ファイルアップロードの例 (OSS SDK for Java)</h1>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">ファイルをアップロード</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);
                        alert('アップロードに失敗しました: ' + error.message);
                    }
                } else {
                    alert('アップロードするファイルを選択してください。');
                }
            });
    
            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(`アップロードに失敗しました、ステータス: ${response.status}`);
                }
    
                alert('ファイルが正常にアップロードされました');
                console.log('ファイルが正常にアップロードされました');
            };
        </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" };  // ContentType を指定します。       
    // カスタムメタデータを設定します。カスタムメタデータは、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("リクエストヘッダー:");
    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($"正常にアップロードされました! ステータスコード: {response.StatusCode}");
        Console.WriteLine("レスポンスヘッダー:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"アップロードに失敗しました! ステータスコード: {response.StatusCode}");
        Console.WriteLine("レスポンスコンテンツ: " + 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 << "ファイルを開けませんでした: " << 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() が失敗しました: " << 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/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, "返されたステータスコード: " + 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 でオブジェクトをアップロードする

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

import argparse
import os
import requests
import alibabacloud_oss_v2 as oss

# コマンドラインパラメータパーサーを作成し、スクリプトの目的を記述します。この例では、マルチパートアップロードを使用してオブジェクトをアップロードするための署名付き URL を生成する方法について説明します。
parser = argparse.ArgumentParser(description="presign multipart upload sample")

# --region パラメータを指定します。これは、バケットが配置されているリージョンを指定します。このコマンドラインパラメータは必須です。
parser.add_argument('--region', help='バケットが配置されているリージョン。', required=True)
# --bucket パラメータを指定します。これは、バケットが配置されているリージョンを指定します。このコマンドラインパラメータは必須です。
parser.add_argument('--bucket', help='バケットの名前。', required=True)
# --endpoint パラメータを指定します。これは、他のサービスが OSS にアクセスするために使用できるエンドポイントを指定します。このコマンドラインパラメータはオプションです。
parser.add_argument('--endpoint', help='他のサービスが OSS にアクセスするために使用できるドメイン名')
# --key パラメータを指定します。これは、オブジェクトの名前を指定します。このコマンドラインパラメータは必須です。
parser.add_argument('--key', help='オブジェクトの名前。', required=True)
# --file_path パラメータを指定します。これは、オブジェクトを保存するパスを指定します。このコマンドラインパラメータは必須です。
parser.add_argument('--file_path', help='アップロードファイルのパス。', required=True)

def main():
    # コマンドラインパラメータを解析して、ユーザーが入力した値を取得します。
    args = parser.parse_args()

    # 環境変数から OSS にアクセスするために必要な認証情報をロードします。
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

    # SDK のデフォルト設定を使用して設定オブジェクトを作成し、認証情報プロバイダーを指定します。
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider

    # ユーザーが指定したコマンドラインパラメータに基づいて、設定オブジェクトのリージョン属性を指定します。
    cfg.region = args.region

    # カスタムエンドポイントが提供されている場合は、設定オブジェクトの endpoint パラメータを変更します。
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    # 前述の設定を使用して OSSClient インスタンスを初期化し、インスタンスが OSS と対話できるようにします。
    client = oss.Client(cfg)

    # パートサイズを 1 MB に設定します。
    part_size = 1024 * 1024
    # ローカルファイルのサイズを取得します。
    data_size = os.path.getsize(args.file_path)
    part_number = 1
    upload_parts = []

    # マルチパートアップロードリクエストを開始します。
    init_pre_result = client.presign(oss.InitiateMultipartUploadRequest(
        bucket=args.bucket,
        key=args.key,
    ))

    # マルチパートアップロードリクエストを送信します。
    with requests.post(init_pre_result.url, headers=init_pre_result.signed_headers) as resp:
        obj = oss.InitiateMultipartUploadResult()
        oss.serde.deserialize_xml(xml_data=resp.content, obj=obj)

        # ローカルファイルを開き、コンテンツを読み取ります。
        with open(args.file_path, 'rb') as f:
            for start in range(0, data_size, part_size):
                n = part_size
                if start + n > data_size:
                    n = data_size - start
                reader = oss.io_utils.SectionReader(oss.io_utils.ReadAtReader(f), start, n)

                # パートの署名付き URL を生成するリクエストを開始します。
                up_pre_result = client.presign(oss.UploadPartRequest(
                    bucket=args.bucket,
                    key=args.key,
                    upload_id=obj.upload_id,
                    part_number=part_number,
                ))

                # ローカルファイルをパートに分割します。
                with requests.put(up_pre_result.url, headers=up_pre_result.signed_headers, data=reader) as up_result:
                    print(f'status code: {up_result.status_code},'
                          f' request id: {up_result.headers.get("x-oss-request-id")},'
                          f' part number: {part_number},'
                          f' hash crc64: {up_result.headers.get("x-oss-hash-crc64ecma")},'
                          f' content md5: {up_result.headers.get("Content-MD5")},'
                          f' etag: {up_result.headers.get("ETag")},'
                          f' server time: {up_result.headers.get("x-oss-server-time")}'
                    )

                    # 各パートの ETag と番号を記録します。
                    upload_parts.append(oss.UploadPart(part_number=part_number, etag=up_result.headers.get("ETag")))
                part_number += 1

        # パートをパート番号でソートします。
        parts = sorted(upload_parts, key=lambda p: p.part_number)

        # マルチパートアップロードリクエストを完了します。
        request = oss.CompleteMultipartUploadRequest(
            bucket=args.bucket,
            key=args.key,
            upload_id=obj.upload_id,
            complete_multipart_upload=oss.CompleteMultipartUpload(
                parts=parts
            )
        )

        # パラメータをシリアル化します。
        op_input = oss.serde.serialize_input(request, oss.OperationInput(
            op_name='CompleteMultipartUpload',
            method='POST',
            bucket=request.bucket,
        ))

        # マルチパートアップロードを使用してローカルファイルをアップロードするリクエストを生成します。
        complete_pre_result = client.presign(request)

        # マルチパートアップロードリクエストを完了します。
        with requests.post(complete_pre_result.url, headers=complete_pre_result.signed_headers, data=op_input.body) as complete_resp:
            result = oss.CompleteMultipartUploadResult()
            oss.serde.deserialize_xml(xml_data=complete_resp.content, obj=result)
            print(f'status code: {complete_resp.status_code},'
                  f' request id: {complete_resp.headers.get("x-oss-request-id")},'
                  f' hash crc64: {complete_resp.headers.get("x-oss-hash-crc64ecma")},'
                  f' content md5: {complete_resp.headers.get("Content-MD5")},'
                  f' etag: {complete_resp.headers.get("ETag")},'
                  f' content length: {complete_resp.headers.get("content-length")},'
                  f' content type: {complete_resp.headers.get("Content-Type")},'
                  f' url: {result.location},'
                  f' encoding type: {result.encoding_type},'
                  f' server time: {complete_resp.headers.get("x-oss-server-time")}'
            )

        # リクエストに対して返されたメソッド、有効期限、および署名付き URL を表示します。
        print(f'method: {complete_pre_result.method},'
              f' expiration: {complete_pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {complete_pre_result.url}'
        )

        # リクエストで署名されたヘッダーを表示します。
        for key, value in complete_pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')

# スクリプトが直接実行されたときに main 関数を呼び出して処理ロジックを開始します。
if __name__ == "__main__":
    main() # スクリプトの関数のエントリポイントを指定します。制御プログラムフローはここから開始されます。

署名付き URL を使用してオブジェクトをアップロードし、アップロードコールバックパラメータを設定する

  1. HTTP PUT リクエストを使用してアップロードを有効にするアップロードコールバックパラメータを含む署名付き URL を生成します。

    import argparse
    import base64
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # コマンドラインパラメータパーサーを作成し、スクリプトの目的を記述します。この例では、HTTP PUT リクエストを許可する署名付き URL を生成する方法について説明します。
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # 必須のリージョン、バケット名、エンドポイント、オブジェクト名を含むコマンドラインパラメータを指定します。
    parser.add_argument('--region', help='バケットが配置されているリージョン。', required=True)
    parser.add_argument('--bucket', help='バケットの名前。', required=True)
    parser.add_argument('--endpoint', help='他のサービスが OSS にアクセスするために使用できるドメイン名')
    parser.add_argument('--key', help='オブジェクトの名前。', required=True)
    
    def main():
        # コマンドラインパラメータを解析します。
        args = parser.parse_args()
    
        # 認証のために環境変数からアクセス認証情報を取得します。
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # デフォルト設定を使用して cfg オブジェクトを作成し、認証情報プロバイダーを指定します。
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # cfg オブジェクトの region 属性をコマンドラインで指定されたリージョンに設定します。
        cfg.region = args.region
    
        # カスタムエンドポイントが提供されている場合は、cfg オブジェクトの endpoint 属性を提供されたエンドポイントで更新します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # 前述の設定を使用して OSSClient インスタンスを初期化します。
        client = oss.Client(cfg)
    
        # カスタムコールバック URL を指定します。
        call_back_url = "http://www.example.com/callback"
        # コールバックパラメータを構築します。コールバック URL とリクエスト本文を指定し、パラメータを Base64 でエンコードします。
        callback=base64.b64encode(str('{\"callbackUrl\":\"' + call_back_url + '\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}').encode()).decode()
        # カスタムコールバック変数を定義し、Base64 でエンコードします。
        callback_var=base64.b64encode('{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}'.encode()).decode()
    
        # リクエストを送信して PUT リクエストを開始し、指定されたオブジェクトの署名付き URL を生成します。
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket,  # バケットの名前。
            key=args.key,  # オブジェクトの名前。
            callback=callback,
            callback_var=callback_var,
        ),expires=timedelta(seconds=3600)) # リクエストの有効期間を指定します。この例では、有効期間は 3,600 秒に設定されています。
    
        # リクエストで指定されたメソッド、有効期限、署名付き URL を表示して、署名付き URL の有効性を確認します。
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # リクエストで署名されたヘッダーを表示します。これらは、リクエストの送信時に HTTP ヘッダーに含まれます。
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # スクリプトが直接実行されたときに main 関数を呼び出して処理ロジックを開始します。
    if __name__ == "__main__":
        main()  # スクリプトのエントリポイントを指定します。制御フローはここから開始されます。
  2. 署名付き URL を使用してオブジェクトをアップロードします。

    curl

    curl -X PUT \
         -H "x-oss-callback: eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9" \
         -H "x-oss-callback-var: eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==" \
         -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******************************************************"

    Python

    import requests
    
    def upload_file(signed_url, file_path, headers=None):
        """
        署名付き URL を使用して OSS にオブジェクトをアップロードします。
    
        :param signed_url: 署名付き URL。
        :param file_path: アップロードするローカルファイルのフルパス。
        :param headers: リクエストヘッダー。このパラメータはオプションです。
        :return: なし
        """
        if not headers:
            headers = {}
    
        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"
    
        headers = {
            "x-oss-callback": "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
            "x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
        }
    
        upload_file(signed_url,  file_path, headers)

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io"
    
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string) error {
    	// ファイルを開きます。
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// コンテンツを読み取ります。
    	fileBytes, err := io.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.Add(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, _ := io.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{
    		"x-oss-callback":     "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
    		"x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers)
    	if err != nil {
    		fmt.Printf("エラーが発生しました: %v\n", err)
    	}
    }
    

    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";
    
            // x-oss-callback と x-oss-callback-var を含むリクエストヘッダーを指定します。
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("x-oss-callback", "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9");
            headers.put("x-oss-callback-var", "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==");
    
            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());
                }
    
                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();
            }
        }
    }       

    PHP

    <?php
    
    function uploadFile($signedUrl, $filePath, $headers = []) {
        // ファイルが存在するかどうかを確認します。
        if (!file_exists($filePath)) {
            echo "ファイルが存在しません: $filePath\n";
            return;
        }
    
        // cURL セッションを初期化します。
        $ch = curl_init();
    
        // cURL オプションを設定します。
        curl_setopt($ch, CURLOPT_URL, $signedUrl);
        curl_setopt($ch, CURLOPT_PUT, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_INFILE, fopen($filePath, 'rb'));
        curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function($key, $value) {
            return "$key: $value";
        }, array_keys($headers), $headers));
    
        // cURL リクエストを実行します。
        $response = curl_exec($ch);
    
        // HTTP ステータスコードをクエリします。
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // cURL セッションを閉じます。
        curl_close($ch);
    
        // 結果を出力します
        echo "ステータスコード: $httpCode\n";
        if ($httpCode == 200) {
            echo "ライブラリを使用してオブジェクトがアップロードされます。\n";
        } else {
            echo "アップロードに失敗しました。\n";
        }
        echo $response . "\n";
    }
    
    // <signedUrl> を署名付き URL に置き換えます。
    $signedUrl = "<signedUrl>";
    
    // ローカルファイルのフルパスを指定します。デフォルトでは、ローカルファイルのフルパスを指定しない場合、スクリプトが保存されているディレクトリからローカルファイルがアップロードされます。
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

FAQ

署名付き URL を使用してローカルファイルをアップロードするときに、アップロード中に署名付き URL の有効期限が切れた場合、ファイルはアップロードされますか?

はい、アップロード中に署名付き URL の有効期限が切れてもファイルはアップロードされます。

アップロード中に署名付き URL が使用されます。URL はその有効期間内に使用できます。URL の有効期間は、トークンの有効期間と署名付きの有効期間の最小値です。

URL を生成するときにリクエストヘッダーとユーザーメタデータを指定しない場合、URL を使用してローカルファイルをアップロードするときにリクエストヘッダーとユーザーメタデータを指定する必要がありますか?

リクエストヘッダーとユーザーメタデータを指定する必要はありません。

リクエストヘッダーとユーザーメタデータはオプションのパラメータです。リクエストヘッダーとユーザーメタデータを指定しない場合は、上記の例の関連コードを削除してください。

参考資料

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

  • 署名付き URL を使用してマルチパートアップロードでオブジェクトをアップロードするための完全なサンプルコードについては、presigner_complete_multipart_upload.py をご参照ください。