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

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

最終更新日:Aug 13, 2025

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

使用上の注意

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

  • このトピックでは、アクセス認証情報は環境変数から取得されます。 アクセス認証情報を設定する方法の詳細については、「アクセス認証情報を設定する (Python SDK V1)」をご参照ください。

  • このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスを作成します。 カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、「初期化」をご参照ください。

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

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

プロセス

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

image

サンプルコード

  1. オブジェクト所有者は、HTTP PUT リクエストを許可する署名付き URL を生成します。

    # -*- coding: utf-8 -*-
    import oss2
    from oss2.credentials import EnvironmentVariableCredentialsProvider
    
    # 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
    auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
    
    # バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
    endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
    
    # バケットが配置されているリージョンを指定します。例: cn-hangzhou。V4 署名アルゴリズムを使用する場合は、このパラメータが必要です。
    region = "cn-hangzhou"
    
    # バケットの名前を指定します。
    bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
    
    # オブジェクトの完全なパスを指定します。例: exampledir/exampleobject.txt。完全なパスにバケット名を含めないでください。
    object_name = 'exampledir/exampleobject.txt'
    
    # ローカルファイルをアップロードするために使用される署名付き URL を生成します。署名付き URL の有効期間を 60 秒に設定します。
    # デフォルトでは、OSS は署名付き URL の生成時に、オブジェクトの完全なパスにあるスラッシュ (/) をエスケープ文字として認識します。したがって、署名付き URL を直接使用することはできません。
    # slash_safe パラメータを True に設定します。こうすることで、OSS はオブジェクトの完全なパスにあるスラッシュ (/) をエスケープ文字として認識しません。この場合、署名付き URL を直接使用できます。
    url = bucket.sign_url('PUT', object_name, 60, slash_safe=True)
    print('The presigned URL:', url) 
  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("Status code returned:"+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("Status code returned: %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"Status code returned: {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(`Status code returned: ${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() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "Status code returned: " << 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, "Status code returned: " + 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 を生成します。

    # -*- coding: utf-8 -*-
    import oss2
    from oss2.credentials import EnvironmentVariableCredentialsProvider
    
    # 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
    auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
    
    # バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
    endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
    
    # バケットが配置されているリージョンを指定します。例: cn-hangzhou。V4 署名アルゴリズムを使用する場合は、このパラメータが必要です。
    region = "cn-hangzhou"
    
    # バケットの名前を指定します。
    bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
    
    # オブジェクトの完全なパスを指定します。例: exampledir/exampleobject.txt。完全なパスにバケット名を含めないでください。
    object_name = 'exampledir/exampleobject.txt'
    
    # リクエストヘッダーを指定します。
    headers = dict()
    # Content-Type ヘッダーを指定します。
    headers['Content-Type'] = 'text/plain; charset=utf8'
    # オブジェクトのストレージクラスを指定します。
    headers["x-oss-storage-class"] = "Standard"
    
    # ユーザーメタデータを指定します。
    metadata = {'key1': 'value1', 'key2': 'value2'}
    # メタデータキーに x-oss-meta- プレフィックスを追加します。
    for key, value in metadata.items():
        headers[f'x-oss-meta-{key}'] = value
    
    # ローカルファイルをアップロードするために使用される署名付き URL を生成します。署名付き URL の有効期間を 60 秒に設定します。
    # デフォルトでは、OSS は署名付き URL の生成時に、オブジェクトの完全なパスにあるスラッシュ (/) をエスケープ文字として認識します。したがって、署名付き URL を直接使用することはできません。
    # slash_safe パラメータを True に設定します。こうすることで、OSS はオブジェクトの完全なパスにあるスラッシュ (/) をエスケープ文字として認識しません。この場合、署名付き URL を直接使用できます。
    url = bucket.sign_url('PUT', object_name, 60, slash_safe=True, headers=headers)
    print('The presigned URL:', url)
  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("Status code returned:"+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("Status code returned: %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"Status code returned: {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(`Status code returned: ${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() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "Status code returned: " << 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, "Status code returned: " + 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();
                }
            }
        }
    }
    

FAQ

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

サーバーがリクエストを受信して署名を検証した場合、ファイルのアップロードは失敗しません。

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

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