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

Object Storage Service:署名付き URL を使用したオブジェクトアップロードの処理

最終更新日:Sep 03, 2026

デフォルトでは、Object Storage Service (OSS) バケット内のオブジェクトのアクセス制御リスト (ACL) は private に設定されており、オブジェクトの所有者のみがアクセス権限を持ちます。ただし、所有者は署名付き URL を生成して、指定された期間内に他のユーザーがオブジェクトをアップロードするための一時的なアクセスを許可できます。この機能により、パートナーが契約書をアップロードしたり、ユーザーがプロフィール画像を送信したりするなどのシナリオが可能になります。

注意事項

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

  • 署名付き URL の生成に権限は必要ありません。ただし、第三者が署名付き URL を使用してファイルを正常にアップロードできるのは、お客様が oss:PutObject 権限を持っている場合に限られます。詳細については、「RAM ユーザーにカスタムアクセスポリシーを付与する」をご参照ください。

  • 署名付き URL は FormData アップロードをサポートしていません。FormData アップロードの場合は、代わりにフォームアップロードを使用してください。

ワークフロー

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

署名付き URL を使用したオブジェクトのアップロード

  1. バケットの所有者は、PUT リクエストを許可する署名付き URL を生成します。

    説明

    OSS SDK を使用して生成された署名付き URL の最大有効期間は 7 日間です。Security Token Service (STS) トークンを使用して署名付き URL を生成する場合、最大 12 時間 (43,200 秒) 有効です。

    Java

    OSS SDK for Java を使用して署名付き URL を生成する方法の詳細については、「OSS SDK for Java」をご参照ください。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;
    
    public class GetSignUrl {
        public static void main(String[] args) throws Throwable {
            // この例では、中国 (杭州) のパブリックエンドポイントを使用します。他のリージョンの場合は、実際の情報に置き換えてください。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 環境変数からアクセス認証情報を取得します。このコードを実行する前に、環境変数 OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET が設定されていることを確認してください。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            //  バケット名を指定します。例: "examplebucket"
            String bucketName = "examplebucket";
            // オブジェクトの完全なパスを指定します。例: "exampleobject.txt"。オブジェクトパスにバケット名を含めないでください。
            String objectName = "exampleobject.txt";
            // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) にある場合は、リージョンを cn-hangzhou に設定します。
            String region = "cn-hangzhou";
    
            // OSSClient インスタンスを作成します。
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            URL signedUrl = null;
            try {
                // 生成された署名付き URL の有効期間をミリ秒単位で指定します。この例では、有効期限を 1 時間に設定しています。
                Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
    
                // 署名付き URL を生成します。
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
                // 署名付き URL の有効期限を設定します。
                request.setExpiration(expiration);
                // HTTP PUT メソッドを許可する署名付き URL を生成します。
                signedUrl = ossClient.generatePresignedUrl(request);
                // 署名付き URL を表示します。
                System.out.println("signed url for putObject: " + signedUrl);
    
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            }
        }
    }       

    Go

    OSS SDK for Go を使用して署名付き URL を生成する方法の詳細については、「OSS SDK for Go」をご参照ください。

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // グローバル変数を定義します。
    var (
    	region     string // バケットのリージョン。
    	bucketName string // バケットの名前。
    	objectName string // オブジェクトの名前。
    )
    
    //  init 関数を定義して、コマンドラインパラメーターを初期化します。
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	// コマンドラインパラメーターを解析します。
    	flag.Parse()
    
    	// バケット名が空かどうかを確認します。
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, bucket name required")
    	}
    
    	// リージョンが空かどうかを確認します。
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// オブジェクト名が空かどうかを確認します。
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, object name required")
    	}
    
    	// デフォルト設定をロードし、認証情報プロバイダーとリージョンを指定します。
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// OSS クライアントインスタンスを作成します。
    	client := oss.NewClient(cfg)
    
    	// PutObject メソッドで署名付き URL を生成します。
    	result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
    		Bucket: oss.Ptr(bucketName),
    		Key:    oss.Ptr(objectName),
    	},
    		oss.PresignExpires(10*time.Minute),
    	)
    	if err != nil {
    		log.Fatalf("failed to put object presign %v", err)
    	}
    
    	log.Printf("request method:%v\n", result.Method)
    	log.Printf("request expiration:%v\n", result.Expiration)
    	log.Printf("request url:%v\n", result.URL)
    	if len(result.SignedHeaders) > 0 {
    		//返された結果に署名ヘッダーが含まれている場合は、署名付き URL で PUT リクエストを行う際に、これらのヘッダーを必ず含めてください。
    		log.Printf("signed headers:\n")
    		for k, v := range result.SignedHeaders {
    			log.Printf("%v: %v\n", k, v)
    		}
    	}
    }
    

    Python

    OSS SDK for Python を使用して署名付き URL を生成する方法の詳細については、「OSS SDK for Python」をご参照ください。

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # コマンドライン引数パーサーを作成し、スクリプトの目的を説明します: オブジェクトの署名付き PUT リクエスト URL を生成する (Presign Put Object)。
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # 必須のリージョン、バケット名、エンドポイント、オブジェクトキーを含むコマンドライン引数を定義します。
    parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
    parser.add_argument('--bucket', help='The name of the bucket.', required=True)
    parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
    parser.add_argument('--key', help='The name of the object.', 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
    
        # カスタムエンドポイントが指定されている場合は、設定オブジェクトのエンドポイントプロパティを更新します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # 上記の設定で OSS クライアントを初期化し、OSS と対話します。
        client = oss.Client(cfg)
    
        # 指定されたオブジェクトの署名付き PUT リクエストを生成するリクエストを送信します。
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket,  # バケット名
            key=args.key,  # オブジェクトキー
        ),expires=timedelta(seconds=3600)) # 有効期限を秒単位で設定します。ここでは 3600 秒に設定されています。
    
        # リンクの有効性を確認するために、署名付きリクエストのメソッド、有効期限、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()  # スクリプトのエントリポイント。プログラムのフローはここから始まります。

    Node.js

    次の例では、通常のアップロード用の署名付き URL を生成します。OSS SDK for Node.js を使用して、画像処理パラメーターまたはバージョン ID を持つ署名付き URL を生成する方法の詳細については、「OSS SDK for Node.js」をご参照ください。

    const OSS = require("ali-oss");
    
    // 署名付き URL を生成する関数を定義します。
    async function generateSignatureUrl(fileName) {
      // 署名付き URL を取得します。
      const client = await new OSS({
          accessKeyId: 'yourAccessKeyId',
          accessKeySecret: 'yourAccessKeySecret',
          bucket: 'examplebucket',
          region: 'oss-cn-hangzhou',
          authorizationV4: true
      });
    
      return await client.signatureUrlV4('PUT', 3600, {
          headers: {} // 実際のリクエストヘッダーに基づいてリクエストヘッダーを設定します。
      }, fileName);
    }
    // 関数を呼び出し、ファイル名を渡します。
    generateSignatureUrl('yourFileName').then(url => {
      console.log('Generated Signature URL:', url);
    }).catch(err => {
      console.error('Error generating signature URL:', err);
    });

    PHP

    次の例では、通常のアップロード用の署名付き URL を生成します。OSS SDK for PHP を使用してバージョン ID を持つ署名付き URL を生成する方法の詳細については、「OSS SDK for PHP」をご参照ください。

    <?php
    if (is_file(__DIR__ . '/../autoload.php')) {
        require_once __DIR__ . '/../autoload.php';
    }
    if (is_file(__DIR__ . '/../vendor/autoload.php')) {
        require_once __DIR__ . '/../vendor/autoload.php';
    }
    
    use OSS\OssClient;
    use OSS\Core\OssException;
    use OSS\Http\RequestCore;
    use OSS\Http\ResponseCore;
    use OSS\Credentials\EnvironmentVariableCredentialsProvider;
    
    // 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
    $provider = new EnvironmentVariableCredentialsProvider();
    // バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
    $endpoint = "yourEndpoint";
    // バケットの名前を指定します。
    $bucket= "examplebucket";
    // オブジェクトの完全なパスを指定します。オブジェクトの完全なパスにバケット名を含めないでください。
    $object = "exampleobject.txt";
    // 署名付き URL の有効期間を 600 秒に設定します。最大値: 32400。
    $timeout = 600;
    try {
        $config = array(  
            "provider" => $provider,
            "endpoint" => $endpoint,
            'signatureVersion'=>OssClient::OSS_SIGNATURE_VERSION_V4,
            "region"=> "cn-hangzhou"
        );
        $ossClient = new OssClient($config);
        // 署名付き URL を生成します。
        $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT");
        print_r($signedUrl);
    } catch (OssException $e) {
        printf(__FUNCTION__ . ": FAILED\n");
        printf($e->getMessage() . "\n");
        return;
    }           

    Android

    OSS SDK for Android を使用して署名付き URL を生成する方法の詳細については、「アクセス権限の付与 (Android SDK)」をご参照ください。

    // バケット名を指定します。例: examplebucket
    String bucketName = "examplebucket";
    // ソースオブジェクトの完全なパスを、バケット名なしで指定します。例: exampleobject.txt
    String objectKey = "exampleobject.txt";
    // content-type を設定します。
    String contentType = "application/octet-stream";
    String url = null;
    try {
        // ファイルをアップロードするための署名付き URL を生成します。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey);
        // 署名付き URL の有効期限を 30 分に設定します。
        request.setExpiration(30*60);
        request.setContentType(contentType);    
        request.setMethod(HttpMethod.PUT);
        url = oss.presignConstrainedObjectURL(request);
        Log.d("url", url);
    } catch (ClientException e) {
        e.printStackTrace();
    }

    C++

    OSS SDK for C++ を使用して署名付き URL を生成する方法の詳細については、「アクセス権限の付与 (C++ SDK)」をご参照ください。

    #include <alibabacloud/oss/OssClient.h>
    using namespace AlibabaCloud::OSS;
    
    int main(void)
    {
        /* OSS へのアクセスに使用するアカウントに関する情報を初期化します。*/
                
        /* バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。*/
        std::string Endpoint = "yourEndpoint";
        /* バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。   * /
        std::string Region = "yourRegion";
        /* バケットの名前を指定します。例: examplebucket */
        std::string BucketName = "examplebucket";
        /* オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。例: exampledir/exampleobject.txt */   
        std::string PutobjectUrlName = "exampledir/exampleobject.txt";
    
         /* ネットワークリソースなどのリソースを初期化します。*/
        InitializeSdk();
    
        ClientConfiguration conf;
        conf.signatureVersion = SignatureVersionType::V4;
        /* 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。*/
        auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
        OssClient client(Endpoint, credentialsProvider, conf);
        client.SetRegion(Region);
    
        /* 署名付き URL の有効期間を指定します。最大有効期間は 32,400 です。単位: 秒。*/
        std::time_t t = std::time(nullptr) + 1200;
        /* 署名付き URL を生成します。*/
        auto genOutcome = client.GeneratePresignedUrl(BucketName, PutobjectUrlName, t, Http::Put);
        if (genOutcome.isSuccess()) {
            std::cout << "GeneratePresignedUrl success, Gen url:" << genOutcome.result().c_str() << std::endl;
        }
        else {
            /* 例外を処理します。*/
            std::cout << "GeneratePresignedUrl fail" <<
            ",code:" << genOutcome.error().Code() <<
            ",message:" << genOutcome.error().Message() <<
            ",requestId:" << genOutcome.error().RequestId() << std::endl;
            return -1;
        }
    
        /* ネットワークリソースなどのリソースを解放します。*/
        ShutdownSdk();
        return 0;
    }

    iOS

    OSS SDK for iOS を使用して署名付き URL を生成する方法の詳細については、「アクセス権限の付与 (iOS SDK)」をご参照ください。

    // バケットの名前を指定します。
    NSString *bucketName = @"examplebucket";
    // オブジェクトの名前を指定します。
    NSString *objectKey = @"exampleobject.txt";
    NSURL *file = [NSURL fileURLWithPath:@"<filePath>"];
    NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey];
    __block NSString *urlString;
    // オブジェクトをアップロードするための有効期間付きの署名付き URL を生成します。この例では、URL の有効期間は 30 分です。
    OSSTask *task = [client presignConstrainURLWithBucketName:bucketName
                                                withObjectKey:objectKey
                                                   httpMethod:@"PUT"
                                       withExpirationInterval:30 * 60
                                               withParameters:@{}
                                                  contentType:contentType
                                                   contentMd5:nil];
    [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
        if (task.error) {
            NSLog(@"presign error: %@", task.error);
        } else {
            urlString = task.result;
            NSLog(@"url: %@", urlString);
        }
        return nil;
    }];

    .NET

    OSS SDK for .NET を使用して署名付き URL を生成する方法の詳細については、「署名付き URL を使用したファイルのアップロード (C# SDK V1)」をご参照ください。

    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    // バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
    var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // 環境変数からアクセス認証情報を取得します。このコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // バケット名を指定します。例: examplebucket
    var bucketName = "examplebucket";
    // オブジェクトの完全なパスを指定します。完全なパスにはバケット名を含めません。例: exampledir/exampleobject.txt
    var objectName = "exampledir/exampleobject.txt";
    var objectContent = "More than just cloud.";
    // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
    const string region = "cn-hangzhou";
    
    // ClientConfiguration インスタンスを作成し、必要に応じてデフォルトパラメーターを変更します。
    var conf = new ClientConfiguration();
    
    // 署名バージョンを V4 に設定します。
    conf.SignatureVersion = SignatureVersion.V4;
    
    // OssClient インスタンスを作成します。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
    client.SetRegion(region);
    try
    {
        // 署名付き URL を生成します。
        var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put)
        {
            // 署名付き URL の有効期限を設定します。デフォルト値は 3600 秒です。
            Expiration = DateTime.Now.AddHours(1),
        };
        var signedUrl = client.GeneratePresignedUri(generatePresignedUriRequest);
    }
    catch (OssException ex)
    {
        Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
            ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Failed with error info: {0}", ex.Message);
    }

    C

    OSS SDK for C を使用して署名付き URL を生成する方法の詳細については、「アクセス権限の付与 (C SDK)」をご参照ください。

    #include "oss_api.h"
    #include "aos_http_io.h"
    /* yourEndpoint を、バケットが配置されているリージョンのエンドポイントに設定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。*/
    const char *endpoint = "yourEndpoint";
    
    /* バケット名を指定します。例: examplebucket */
    const char *bucket_name = "examplebucket";
    /* オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めることはできません。例: exampledir/exampleobject.txt */
    const char *object_name = "exampledir/exampleobject.txt";
    /* ローカルファイルの完全なパスを指定します。*/
    const char *local_filename = "yourLocalFilename";
    void init_options(oss_request_options_t *options)
    {
        options->config = oss_config_create(options->pool);
        /* aos_string_t 型を char* 文字列で初期化します。*/
        aos_str_set(&options->config->endpoint, endpoint);
        /* 環境変数からアクセス認証情報を取得します。このサンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。*/
        aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
        aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
        /* CNAME を使用して OSS にアクセスするかどうかを指定します。値 0 は CNAME が使用されないことを示します。*/
        options->config->is_cname = 0;
        /* タイムアウト期間などのネットワークパラメーターを設定します。*/
        options->ctl = aos_http_controller_create(options->pool, 0);
    }
    int main(int argc, char *argv[])
    {
        /* プログラムエントリで aos_http_io_initialize メソッドを呼び出して、ネットワークやメモリなどのグローバルリソースを初期化します。*/
        if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
            exit(1);
        }
        /* メモリ管理用のメモリプール (pool)。apr_pool_t と同等です。その実装コードは APR ライブラリにあります。*/
        aos_pool_t *pool;
        /* 新しいメモリプールを作成します。2 番目のパラメーターは NULL で、プールが他のメモリプールから継承しないことを示します。*/
        aos_pool_create(&pool, NULL);
        /* オプションを作成して初期化します。このパラメーターには、endpoint、access_key_id、access_key_secret、is_cname、curl などのグローバル設定情報が含まれます。*/
        oss_request_options_t *oss_client_options;
        /* メモリプール内のオプションにメモリを割り当てます。*/
        oss_client_options = oss_request_options_create(pool);
        /* クライアントオプション oss_client_options を初期化します。*/
        init_options(oss_client_options);
        /* パラメーターを初期化します。*/
        aos_string_t bucket;
        aos_string_t object;
        aos_string_t file;    
        aos_http_request_t *req;
        apr_time_t now;
        char *url_str;
        aos_string_t url;
        int64_t expire_time; 
        int one_hour = 3600;
        aos_str_set(&bucket, bucket_name);
        aos_str_set(&object, object_name);
        aos_str_set(&file, local_filename);
        expire_time = now / 1000000 + one_hour;    
        req = aos_http_request_create(pool);
        req->method = HTTP_PUT;
        now = apr_time_now(); 
        /* 単位: マイクロ秒。*/
        expire_time = now / 1000000 + one_hour;
        /* 署名付き URL を生成します。*/
        url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req);
        aos_str_set(&url, url_str);
        printf("Temporary upload URL: %s\n", url_str);    
        /* メモリプールを解放します。これは、リクエスト中にさまざまなリソースに割り当てられたメモリを解放することに相当します。*/
        aos_pool_destroy(pool);
        /* 以前に割り当てられたグローバルリソースを解放します。*/
        aos_http_io_deinitialize();
        return 0;
    }
  1. 他のユーザーは、署名付き URL を使用して PUT リクエストを送信し、オブジェクトをアップロードします。

    重要

    署名付き URL は、有効期限が切れるまで複数回使用できます。ただし、同じオブジェクトを複数回アップロードすると、新しいアップロードごとに前のものが上書きされます。URL の有効期限が切れると、所有者は新しい署名付き URL を生成して (「ステップ 1」を参照)、他のユーザーが長期間アクセスできるようにする必要があります。

署名付き URL を使用したオブジェクトのパート単位でのアップロード

ラージオブジェクトをアップロードする必要があるものの、クライアントに OSS SDK を統合することが困難または不可能な場合は、署名付き URL を使用したマルチパートアップロードを検討してください。このアプローチでは、サーバーがアップロードプロセスを開始し、各パートに署名付き URL が割り当てられ、クライアントまたはサードパーティのサービスが個別にアップロードします。すべてのパートが正常にアップロードされると、サーバーはそれらを結合して完全なオブジェクトにします。

重要

署名付き URL を使用してオブジェクトをパート単位でアップロードするのは、OSS SDK を使用するよりも複雑です。署名付き URL を使用してオブジェクトをパート単位でアップロードする場合、クライアントが署名付き URL で指定されたパート番号に対応するパートをアップロードするようにしてください。パートの欠落や不一致があると、パートの結合に失敗します。クライアントが SDK 統合をサポートしている場合は、よりシンプルで安定性の高い STS トークンに基づくクライアント直接アップロードを使用することを推奨します。

  1. クライアントがマルチパートアップロードリクエストを送信します。

    クライアントは、オブジェクト名、オブジェクトサイズ、パートサイズを含むマルチパートアップロードリクエストを送信します。パートサイズは最大 5 GB に制限されており、推奨値は 5 MB です。

    次のコードは、クライアントから送信されるマルチパートアップロードの例です。この例を使用する際は、https://yourserver.com/init-upload をご使用のサーバー上の実際の初期化エンドポイントに置き換えてください。

    curl -X POST https://yourserver.com/init-upload \
      -H "Content-Type: application/json" \
      -d '{
        "fileName": "exampleobject.jpg",
        "fileSize": 104857600,
        "partSize": 5242880
    }'
  2. サーバーがマルチパートアップロードを開始し、署名付き URL を生成します。

    1. InitiateMultipartUpload を呼び出してアップロードを開始し、アップロード ID を取得します。

    2. オブジェクトサイズとパートサイズに基づいてパート数を計算します。

    3. 各パートの署名付き URL を生成します。

    4. 署名付き URL のリストを JSON 形式で返します。

    説明

    サーバーはアップロード ID を記録します。これはマルチパートアップロードを一意に識別し、パートの検証と結合に使用されます。アップロード ID は、キャッシュ、データベース、またはその他の方法で保存できます。

    マルチパートアップロードを開始し、署名付き URL を生成するためのサンプルコード

    Java

    import com.aliyun.oss.ClientBuilderConfiguration;
    import com.aliyun.oss.HttpMethod;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.InitiateMultipartUploadRequest;
    import com.aliyun.oss.model.InitiateMultipartUploadResult;
    
    import java.net.URL;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    public class InitAndGenerateURL {
        public static void main(String[] args) throws Throwable {
            // クライアントが提供するファイルサイズとパートサイズをバイト単位でシミュレートします。
            long fileSize = 15 * 1024 * 1024L;   // 15 MB のファイルサイズをシミュレートします。
            long partSize = 5 * 1024 * 1024L;    // 5 MB のパートサイズをシミュレートします。
    
            // パート数を計算します。
            int totalParts = (int) ((fileSize + partSize - 1) / partSize);
    
            // OSS にアクセスするためのエンドポイントを指定します。
            // この例では、中国 (杭州) リージョンのエンドポイントを使用します。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            String region = "cn-hangzhou";
            String bucketName = "exampleBucket";
            String objectName = "exampleObject.jpeg";
            long expireTime = 3600 * 1000L; // URL が 1 時間有効であることを指定します。
    
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            ClientBuilderConfiguration config = new ClientBuilderConfiguration();
            config.setSignatureVersion(SignVersion.V4);
    
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .region(region)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(config)
                    .build();
    
            // マルチパートアップロードを開始します。
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
            InitiateMultipartUploadResult initResult = ossClient.initiateMultipartUpload(initRequest);
            String uploadId = initResult.getUploadId();
            System.out.println("Upload ID: " + uploadId);
            System.out.println("Total parts: " + totalParts);
    
            // 各パートの署名付き URL を生成します。
            for (int i = 1; i <= totalParts; i++) {
                Map<String, String> headers = new HashMap<>();
                String signedUrl = generatePresignedUrl(ossClient, bucketName, objectName, HttpMethod.PUT,
                        expireTime, i, uploadId, headers);
                System.out.println("Part " + i + " URL: " + signedUrl);
            }
    
            ossClient.shutdown();
        }
    
        public static String generatePresignedUrl(OSS ossClient, String bucketName, String objectName, HttpMethod method,
                                                  long expireTime, int partNum, String uploadId, Map<String, String> headers) {
            Date expiration = new Date(System.currentTimeMillis() + expireTime);
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, method);
            request.setExpiration(expiration);
            request.setHeaders(headers);
            request.addQueryParameter("partNumber", String.valueOf(partNum));
            request.addQueryParameter("uploadId", uploadId);
            URL url = ossClient.generatePresignedUrl(request);
            return url.toString();
        }
    }
    

    Go

    package main
    
    import (
    	"context"
    	"encoding/json"
    	"flag"
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    type SignedPart struct {
    	PartNumber int    `json:"part_number"`
    	URL        string `json:"url"`
    	Method     string `json:"method"`
    }
    
    type UploadInitResponse struct {
    	UploadId string       `json:"upload_id"`
    	Parts    []SignedPart `json:"parts"`
    }
    
    // グローバル変数を定義します。
    var (
    	region     string
    	bucketName string
    	objectName string
    )
    
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	flag.Parse()
    
    	// ファイルサイズが 15 MB、パートサイズが 5 MB であると仮定します。
    	fileSize := int64(15 * 1024 * 1024)
    	partSize := int64(5 * 1024 * 1024)
    	totalParts := int((fileSize + partSize - 1) / partSize)
    
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	client := oss.NewClient(cfg)
    
    	// マルチパートアップロードを開始します。
    	resp, err := client.InitiateMultipartUpload(context.TODO(), &oss.InitiateMultipartUploadRequest{
    		Bucket: oss.Ptr(bucketName),
    		Key:    oss.Ptr(objectName),
    	})
    	if err != nil {
    		log.Fatalf("Failed to initiate multipart upload: %v", err)
    	}
    	uploadId := resp.UploadId
    	fmt.Println("Upload ID:", *uploadId)
    	fmt.Println("Total parts:", totalParts)
    
    	// 各パートの署名付き URL を生成します。
    	expire := time.Hour // 署名付き URL の有効期間を 1 時間に設定します。
    	var parts []SignedPart
    	for i := 1; i <= totalParts; i++ {
    		req := &oss.UploadPartRequest{
    			Bucket:     oss.Ptr(bucketName),
    			Key:        oss.Ptr(objectName),
    			PartNumber: int32(i),
    			UploadId:   uploadId,
    		}
    		presignResult, err := client.Presign(context.TODO(), req, oss.PresignExpiration(time.Now().Add(expire)))
    		if err != nil {
    			log.Fatalf("Failed to generate signed URL for part %d: %v", i, err)
    		}
    		parts = append(parts, SignedPart{
    			PartNumber: i,
    			URL:        presignResult.URL,
    			Method:     "PUT",
    		})
    	}
    
    	// JSON で応答を表示します。
    	out := UploadInitResponse{
    		UploadId: *uploadId,
    		Parts:    parts,
    	}
    	outJSON, _ := json.MarshalIndent(out, "", "  ")
    	fmt.Println(string(outJSON))
    }
    

    Python

    import argparse
    import json
    import alibabacloud_oss_v2 as oss
    
    # パラメーターをシミュレートします。
    FILE_SIZE = 15 * 1024 * 1024  # 15 MB のファイルサイズをシミュレートします。
    PART_SIZE = 5 * 1024 * 1024   # 5 MB のパートサイズをシミュレートします。
    EXPIRE_TIME = 3600            # 3,600 秒の URL 有効期間をシミュレートします。
    
    def main():
        # コマンドライン引数パーサーを作成し、スクリプトの目的を説明します。
        parser = argparse.ArgumentParser(description="presign multipart upload sample")
    
        # バケットのリージョンを指定するための --region 引数を追加します。この引数は必須です。
        parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
        # バケットを指定するための --bucket 引数を追加します。この引数は必須です。
        parser.add_argument('--bucket', help='The name of the bucket.', required=True)
        # OSS にアクセスするためのエンドポイントを指定するための --endpoint 引数を追加します。この引数はオプションです。
        parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
        # オブジェクトの名前を指定するための --key 引数を追加します。この引数は必須です。
        parser.add_argument('--key', help='The name of the object.', required=True)
    
        args = parser.parse_args()
    
        # OSS クライアントを初期化するための設定を作成します。
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
        cfg.region = args.region
        # エンドポイントが指定されている場合は、それを使用します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
        
        # OSS クライアントを初期化します。
        client = oss.Client(cfg)
    
        # マルチパートアップロード開始リクエストを送信し、アップロード ID を取得します。
        init_result = client.presign(oss.InitiateMultipartUploadRequest(
            bucket=args.bucket,
            key=args.key,
        ))
    
        # 署名付き URL を使用してアップロードを開始し、アップロード ID を取得します。
        import requests
        with requests.post(init_result.url, headers=init_result.signed_headers) as resp:
            obj = oss.InitiateMultipartUploadResult()
            oss.serde.deserialize_xml(xml_data=resp.content, obj=obj)
            upload_id = obj.upload_id
    
        # パート数を計算し、各パートの署名付き URL を生成します。
        total_parts = (FILE_SIZE + PART_SIZE - 1) // PART_SIZE
        parts = []
    
        for part_number in range(1, total_parts + 1):
            req = oss.UploadPartRequest(
                bucket=args.bucket,
                key=args.key,
                part_number=part_number,
                upload_id=upload_id,
                expiration_in_seconds=EXPIRE_TIME
            )
            presign_result = client.presign(req)
            parts.append({
                "part_number": part_number,
                "url": presign_result.url,
                "method": "PUT"
            })
    
        # アップロード ID とすべてのパートの署名付き URL を JSON で表示します。
        output = {
            "upload_id": upload_id,
            "parts": parts
        }
    
        print(json.dumps(output, indent=2))
    
    if __name__ == "__main__":
        main()
  3. クライアントがオブジェクトをパート単位でアップロードします。

    クライアントは、サーバーから返された署名付き URL を使用して、個々のパートをアップロードするために PUT リクエストを送信します。各パートは、「署名付き URL を使用したオブジェクトのアップロード」と同様の方法でアップロードされます。すべてのパートがアップロードされた後、クライアントはサーバーにパートの結合を通知します。

    説明

    署名付き URL を介したマルチパートアップロードは並行処理をサポートしていますが、各 URL が指定されたパート専用に使用されることを確認することが重要です。たとえば、URL 内のパート番号 N は、ファイルの N 番目のパートをアップロードするために使用する必要があり、パート番号の再利用やスキップは許可されません。

    次のサンプルコマンドは、最初のパートをアップロードします (/path/to/local/file はローカルファイルのパスです):

    curl -X PUT -T /path/to/local/file "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.jpg?partNumber=1\u0026uploadId=BE2D0BC931BE4DE1B23F339AABFA49EE\u0026x-oss-credential=LTAI********************%2F20250520%2Fcn-hangzhou%2Foss%2Faliyun_v4_request\u0026x-oss-date=20250520T082728Z\u0026x-oss-expires=3600\u0026x-oss-signature=81f3d2e5eaa67c432291577ed20af3b3f60df05ab3cddedcdce168ef707f7ad0\u0026x-oss-signature-version=OSS4-HMAC-SHA256"
  4. (オプション) サーバーがアップロードされたパートを検証します。

    オプションで、パートアップロード完了の通知を受けたときに、サーバーがアップロードされたパートを検証するように設定できます。

    • アップロードされたパートの整合性を検証します。

    • 各パートが期待されるサイズであることを検証します。

    説明

    パートの検証には、以前に記録されたアップロード ID が必要です。

    パートを検証するためのサンプルコード

    Java

    import com.aliyun.oss.ClientBuilderConfiguration;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.*;
    
    import java.util.ArrayList;
    import java.util.List;
    public class complete {
    
        public static void main(String[] args) throws Exception {
            // バケットのリージョンのエンドポイントを指定します。この例では、中国 (杭州) リージョンのエンドポイントです。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // バケットの名前を指定します。
            String bucketName = "examplebucket";
            // オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。
            String objectName = "exampleobject.jpeg";
            // アップロード ID を指定します。
            String uploadId = "4B78****************************";
            // バケットのリージョン ID を指定します。
            String region = "cn-hangzhou";
    
            // 環境変数に保存されている認証情報を使用して OSS クライアントを作成します。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            ClientBuilderConfiguration config = new ClientBuilderConfiguration();
            config.setSignatureVersion(SignVersion.V4);
    
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .region(region)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(config)
                    .build();
    
            try {
                // マルチパートアップロードでアップロードされたすべてのパートをリストします。
                ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);
                PartListing partListing = ossClient.listParts(listPartsRequest);
    
                // パートの ETag を収集します。ETag は後でパートの結合に使用されます。
                List<PartETag> partETags = new ArrayList<>();
                for (PartSummary part : partListing.getParts()) {
                    partETags.add(new PartETag(part.getPartNumber(), part.getETag()));
                }
    
                if (partETags.isEmpty()) {
                    System.out.println("No uploaded parts. The operation stopped.");
                    return;
                }
    
                // パートを結合します。
                System.out.println("Combining parts...");
                CompleteMultipartUploadRequest completeRequest =
                        new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
    
                CompleteMultipartUploadResult result = ossClient.completeMultipartUpload(completeRequest);
                System.out.println("Parts combined.");
                System.out.println("ETag: " + result.getETag());
    
            } catch (Exception e) {
                System.err.println("Part combination failed: " + e.getMessage());
                e.printStackTrace();
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
    }
    

    Go

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    var (
    	region     string
    	bucketName string
    	objectName string
    	uploadId   string
    )
    
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    	flag.StringVar(&uploadId, "uploadId", "", "The upload ID.")
    }
    
    func main() {
    	flag.Parse()
    
    	if region == "" || bucketName == "" || objectName == "" || uploadId == "" {
    		flag.PrintDefaults()
    		log.Fatal("Missing required parameters.")
    	}
    
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	client := oss.NewClient(cfg)
    
    	// アップロードされたパートをリストします。
    	partListResp, err := client.ListParts(context.TODO(), &oss.ListPartsRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    	})
    	if err != nil {
    		log.Fatalf("failed to list parts: %v", err)
    	}
    
    	var parts []oss.UploadPart
    	for _, p := range partListResp.Parts {
    		parts = append(parts, oss.UploadPart{
    			PartNumber: p.PartNumber,
    			ETag:       p.ETag,
    		})
    	}
    
    	// アップロードされたパートを結合します。
    	completeResult, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
    			Parts: parts,
    		},
    	})
    	if err != nil {
    		log.Fatalf("failed to complete multipart upload: %v", err)
    	}
    
    	// 結合結果を表示します。
    	log.Println("Upload completed successfully.")
    	log.Printf("Bucket:   %s\n", oss.ToString(completeResult.Bucket))
    	log.Printf("Key:      %s\n", oss.ToString(completeResult.Key))
    	log.Printf("ETag:     %s\n", oss.ToString(completeResult.ETag))
    	log.Printf("Status:   %s\n", completeResult.Status)
    }
    

    Python

    # -*- coding: utf-8 -*-
    import argparse
    import alibabacloud_oss_v2 as oss
    
    def main():
        # コマンドライン引数パーサーを作成し、スクリプトの目的を説明します。
        parser = argparse.ArgumentParser(description="presign multipart upload sample")
        # バケットのリージョンを指定するための --region 引数を追加します。この引数は必須です。
        parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
        # バケットを指定するための --bucket 引数を追加します。この引数は必須です。
        parser.add_argument('--bucket', help='The name of the bucket.', required=True)
        # OSS にアクセスするためのエンドポイントを指定するための --endpoint 引数を追加します。この引数はオプションです。
        parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
        # オブジェクトの名前を指定するための --key 引数を追加します。この引数は必須です。
        parser.add_argument('--key', help='The name of the object.', required=True)
        # アップロード ID を指定するための --upload_id 引数を追加します。この引数は必須です。
        parser.add_argument('--upload_id', help='The upload ID to list parts for.',required=True)
    
        args = parser.parse_args()
    
        # OSS クライアントを初期化するための設定と認証情報を指定します。
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
        cfg.region = args.region
        if args.endpoint:
            cfg.endpoint = args.endpoint
    
        client = oss.Client(cfg)
    
        try:
            # アップロードされたすべてのパートをリストします。
            list_parts_result = client.list_parts(oss.ListPartsRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id
            ))
    
            # アップロードされたパートのリストを構築します。
            upload_parts = [
                oss.UploadPart(part_number=part.part_number, etag=part.etag)
                for part in list_parts_result.parts
            ]
    
            if not upload_parts:
                print("No uploaded parts found. The operation stopped.")
                return
    
            # パート結合リクエストを構築して実行します。
            request = oss.CompleteMultipartUploadRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id,
                complete_multipart_upload=oss.CompleteMultipartUpload(parts=upload_parts)
            )
    
            result = client.complete_multipart_upload(request)
    
            print("Parts combined.")
            print(f"ETag: {result.etag}")
            print(f"Bucket: {result.bucket}")
            print(f"Key: {result.key}")
    
        except Exception as e:
            print("Part combination failed:", e)
    
    if __name__ == "__main__":
        main()
  5. サーバーがパートを結合し、アップロード結果を返します。

    パートの検証が成功した後、サーバーは CompleteMultipartUpload 操作を呼び出してパートを完全なオブジェクトに結合し、アップロード結果をクライアントに返します。

    パートを結合するためのサンプルコード

    Java

    import com.aliyun.oss.ClientBuilderConfiguration;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.*;
    
    import java.util.ArrayList;
    import java.util.List;
    public class complete {
    
        public static void main(String[] args) throws Exception {
            // バケットのリージョンのエンドポイントを指定します。この例では、中国 (杭州) リージョンのエンドポイントです。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // バケットの名前を指定します。
            String bucketName = "examplebucket";
            // オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。
            String objectName = "exampleobject.jpeg";
            // アップロード ID を指定します。
            String uploadId = "4B78****************************";
            // バケットのリージョン ID を指定します。
            String region = "cn-hangzhou";
    
            // 環境変数に保存されている認証情報を使用して OSS クライアントを作成します。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            ClientBuilderConfiguration config = new ClientBuilderConfiguration();
            config.setSignatureVersion(SignVersion.V4);
    
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .region(region)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(config)
                    .build();
    
            try {
                // マルチパートアップロードでアップロードされたすべてのパートをリストします。
                ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);
                PartListing partListing = ossClient.listParts(listPartsRequest);
    
                // パートの ETag を収集します。ETag は後でパートの結合に使用されます。
                List<PartETag> partETags = new ArrayList<>();
                for (PartSummary part : partListing.getParts()) {
                    partETags.add(new PartETag(part.getPartNumber(), part.getETag()));
                }
    
                if (partETags.isEmpty()) {
                    System.out.println("No uploaded parts. The operation stopped.");
                    return;
                }
    
                // パートを結合します。
                System.out.println("Combining parts...");
                CompleteMultipartUploadRequest completeRequest =
                        new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
    
                CompleteMultipartUploadResult result = ossClient.completeMultipartUpload(completeRequest);
                System.out.println("Parts combined.");
                System.out.println("ETag: " + result.getETag());
    
            } catch (Exception e) {
                System.err.println("Part combination failed: " + e.getMessage());
                e.printStackTrace();
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
    }
    

    Go

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    var (
    	region     string
    	bucketName string
    	objectName string
    	uploadId   string
    )
    
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    	flag.StringVar(&uploadId, "uploadId", "", "The upload ID.")
    }
    
    func main() {
    	flag.Parse()
    
    	if region == "" || bucketName == "" || objectName == "" || uploadId == "" {
    		flag.PrintDefaults()
    		log.Fatal("Missing required parameters.")
    	}
    
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	client := oss.NewClient(cfg)
    
    	// アップロードされたパートをリストします。
    	partListResp, err := client.ListParts(context.TODO(), &oss.ListPartsRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    	})
    	if err != nil {
    		log.Fatalf("failed to list parts: %v", err)
    	}
    
    	var parts []oss.UploadPart
    	for _, p := range partListResp.Parts {
    		parts = append(parts, oss.UploadPart{
    			PartNumber: p.PartNumber,
    			ETag:       p.ETag,
    		})
    	}
    
    	// アップロードされたパートを結合します。
    	completeResult, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
    			Parts: parts,
    		},
    	})
    	if err != nil {
    		log.Fatalf("failed to complete multipart upload: %v", err)
    	}
    
    	// 結合結果を表示します。
    	log.Println("Upload completed successfully.")
    	log.Printf("Bucket:   %s\n", oss.ToString(completeResult.Bucket))
    	log.Printf("Key:      %s\n", oss.ToString(completeResult.Key))
    	log.Printf("ETag:     %s\n", oss.ToString(completeResult.ETag))
    	log.Printf("Status:   %s\n", completeResult.Status)
    }
    

    Python

    # -*- coding: utf-8 -*-
    import argparse
    import alibabacloud_oss_v2 as oss
    
    def main():
        # コマンドライン引数パーサーを作成し、スクリプトの目的を説明します。
        parser = argparse.ArgumentParser(description="presign multipart upload sample")
        # バケットのリージョンを指定するための --region 引数を追加します。この引数は必須です。
        parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
        # バケットを指定するための --bucket 引数を追加します。この引数は必須です。
        parser.add_argument('--bucket', help='The name of the bucket.', required=True)
        # OSS にアクセスするためのエンドポイントを指定するための --endpoint 引数を追加します。この引数はオプションです。
        parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
        # オブジェクトの名前を指定するための --key 引数を追加します。この引数は必須です。
        parser.add_argument('--key', help='The name of the object.', required=True)
        # アップロード ID を指定するための --upload_id 引数を追加します。この引数は必須です。
        parser.add_argument('--upload_id', help='The upload ID to list parts for.',required=True)
    
        args = parser.parse_args()
    
        # OSS クライアントを初期化するための設定と認証情報を指定します。
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
        cfg.region = args.region
        if args.endpoint:
            cfg.endpoint = args.endpoint
    
        client = oss.Client(cfg)
    
        try:
            # アップロードされたすべてのパートをリストします。
            list_parts_result = client.list_parts(oss.ListPartsRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id
            ))
    
            # アップロードされたパートのリストを構築します。
            upload_parts = [
                oss.UploadPart(part_number=part.part_number, etag=part.etag)
                for part in list_parts_result.parts
            ]
    
            if not upload_parts:
                print("No uploaded parts found. The operation stopped.")
                return
    
            # パート結合リクエストを構築して実行します。
            request = oss.CompleteMultipartUploadRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id,
                complete_multipart_upload=oss.CompleteMultipartUpload(parts=upload_parts)
            )
    
            result = client.complete_multipart_upload(request)
    
            print("Parts combined.")
            print(f"ETag: {result.etag}")
            print(f"Bucket: {result.bucket}")
            print(f"Key: {result.key}")
    
        except Exception as e:
            print("Part combination failed:", e)
    
    if __name__ == "__main__":
        main()

ヘッダーを設定してアップロードポリシーを指定

事前署名付き URL を生成する際に、Header パラメーターを指定することでアップロードポリシーを定義できます。たとえば、x-oss-storage-class (ストレージクラスの定義) や Content-Type (オブジェクトタイプの指定) などのヘッダーを設定できます。

重要

署名付き URL の生成時にヘッダーを含めた場合、オブジェクトのアップロード時にも同じヘッダーを提供する必要があります。ヘッダーが一致しない場合、OSS は署名検証の失敗により 403 エラーを返します。

サポートされているヘッダーの詳細については、「PutObject」をご参照ください。また、カスタムヘッダーを設定してオブジェクトメタデータを管理することもできます。詳細については、「オブジェクトメタデータの管理」をご参照ください。

  1. オブジェクトの所有者は、Header パラメーターを使用して署名付き URL を生成します。

    Java

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.StorageClass;
    
    import java.net.URL;
    import java.util.*;
    import java.util.Date;
    
    public class GetSignUrl {
        public static void main(String[] args) throws Throwable {
            // この例では、中国 (杭州) リージョンのパブリックエンドポイントを使用します。実際のエンドポイントを指定してください。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // バケット名を指定します。例: examplebucket
            String bucketName = "examplebucket";
            // オブジェクトの完全なパスを指定します。例: exampleobject.txt。オブジェクトの完全なパスにバケット名を含めることはできません。
            String objectName = "exampleobject.txt";
            // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
            String region = "cn-hangzhou";
    
            // OSSClient インスタンスを作成します。
            // OSSClient インスタンスが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            // リクエストヘッダーを設定します。
            Map<String, String> headers = new HashMap<String, String>();
            // StorageClass を指定します。
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            // ContentType を指定します。
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain; charset=utf8");
    
            // カスタムユーザーメタデータを設定します。
            Map<String, String> userMetadata = new HashMap<String, String>();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            URL signedUrl = null;
            try {
                // 生成された署名付き URL の有効期限をミリ秒単位で指定します。この例では、有効期限を 1 時間に設定しています。
                Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
    
                // 署名付き URL を生成します。
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
                // 有効期限を設定します。
                request.setExpiration(expiration);
    
                // リクエストにリクエストヘッダーを追加します。
                request.setHeaders(headers);
                // カスタムユーザーメタデータを追加します。
                request.setUserMetadata(userMetadata);
    
                // HTTP PUT リクエスト用の署名付き URL を生成します。
                signedUrl = ossClient.generatePresignedUrl(request);
                // 署名付き URL を出力します。
                System.out.println("signed url for putObject: " + signedUrl);
    
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            }
        }
    }       

    Go

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // グローバル変数を定義します
    var (
    	region     string // ストレージリージョン
    	bucketName string // バケット名
    	objectName string // オブジェクト名
    )
    
    // init 関数はコマンドライン引数を初期化するために使用されます
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	// コマンドライン引数を解析します
    	flag.Parse()
    
    	// バケット名が空かどうかを確認します
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, bucket name required")
    	}
    
    	// リージョンが空かどうかを確認します
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// オブジェクト名が空かどうかを確認します
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, object name required")
    	}
    
    	// デフォルト設定をロードし、認証情報プロバイダーとリージョンを設定します
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// OSS クライアントを作成します
    	client := oss.NewClient(cfg)
    
    	// PutObject の署名付き URL を生成します
    	result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
    		Bucket:      oss.Ptr(bucketName),
    		Key:         oss.Ptr(objectName),
    		ContentType:  oss.Ptr("text/plain;charset=utf8"),                    // サーバーサイドでこの署名 URL を生成する際に設定した ContentType と、URL を使用する際に設定した ContentType が一致することを確認してください
    		StorageClass: oss.StorageClassStandard,                              // サーバーサイドでこの署名 URL を生成する際に設定した StorageClass と、URL を使用する際に設定した StorageClass が一致することを確認してください
    		Metadata:    map[string]string{"key1": "value1", "key2": "value2"}, // サーバーサイドでこの署名 URL を生成する際に設定した Metadata と、URL を使用する際に設定した Metadata が一致することを確認してください
    	},
    		oss.PresignExpires(10*time.Minute),
    	)
    	if err != nil {
    		log.Fatalf("failed to put object presign %v", err)
    	}
    
    	log.Printf("request method:%v\n", result.Method)
    	log.Printf("request expiration:%v\n", result.Expiration)
    	log.Printf("request url:%v\n", result.URL)
    	if len(result.SignedHeaders) > 0 {
    		//応答結果に署名ヘッダーが含まれている場合、署名付き URL を使用して Put リクエストを送信する際には、対応するリクエストヘッダーを設定する必要があります
    		log.Printf("signed headers:\n")
    		for k, v := range result.SignedHeaders {
    			log.Printf("%v: %v\n", k, v)
    		}
    	}
    }
    

    Python

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # コマンドライン引数パーサーを作成し、スクリプトの目的を説明します: オブジェクトの署名付き PUT リクエスト URL を生成する (Presign Put Object)。
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # 必須のリージョン、バケット名、エンドポイント、オブジェクトキーを含むコマンドライン引数を定義します。
    parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
    parser.add_argument('--bucket', help='The name of the bucket.', required=True)
    parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
    parser.add_argument('--key', help='The name of the object.', 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
    
        # カスタムエンドポイントが指定されている場合は、設定オブジェクトのエンドポイントプロパティを更新します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # 上記の設定で OSS クライアントを初期化し、OSS と対話します。
        client = oss.Client(cfg)
    
        # 指定されたオブジェクトの署名付き PUT リクエストを生成するリクエストを送信します。
        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)) # 有効期限を秒単位で設定します。ここでは 3600 秒に設定されています。
    
    
        # リンクの有効性を確認するために、署名付きリクエストのメソッド、有効期限、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 "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;
    
            //  を署名付き URL に置き換えます。
            URL signedUrl = new URL("");
    
            // ローカルファイルの完全なパスを指定します。デフォルトでは、ローカルファイルの完全なパスを指定しない場合、ローカルファイルはサンプルプログラムが属するプロジェクトのパスからアップロードされます。
            String pathName = "C:\\Users\\demo.txt";
    
            // リクエストヘッダーを指定します。リクエストヘッダーの値が、署名付き URL が生成されたときのリクエストヘッダーの値と同じであることを確認してください。
            Map headers = new HashMap();
            //ストレージクラスを指定します。
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            //コンテンツタイプを指定します。
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // ユーザーメタデータを指定します。ユーザーメタデータが、署名付き URL が生成されたときのユーザーメタデータと同じであることを確認してください。
            Map userMetadata = new HashMap();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // 署名付き URL が生成されたときにユーザーメタデータやストレージクラスなどのヘッダーを設定した場合、署名付き URL を使用してファイルをアップロードする際にこれらのヘッダーをサーバーに送信する必要があります。署名計算のためにサーバーに送信されるヘッダーが、署名付き URL が生成されたときに指定されたヘッダーと一致しない場合、署名エラーが報告されます。
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
                for(Map.Entry meta: userMetadata.entrySet()){
                    // ユーザーメタデータが指定されている場合、SDK はユーザーメタデータキーに "x-oss-meta-" プレフィックスを追加します。他の方法でファイルをアップロードする場合は、ユーザーメタデータキーにも "x-oss-meta-" プレフィックスが追加されていることを確認してください。
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Status code of the upload: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the network library");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error {
    	// ローカルファイルを開く
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// オブジェクトのコンテンツを読み取る
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// リクエストを作成する
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// リクエストヘッダーを指定する
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// ユーザーメタデータを指定する
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// リクエストを送信する
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// 応答を処理する
    	fmt.Printf("Status code: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("The object is uploaded by using the network library")
    	} else {
    		fmt.Println("Upload failed")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	//  を署名付き URL に置き換えます。
    	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",
    	}, headers, metadata)
    	if err != nil {
    		fmt.Printf("An error occurred: %v\n", err)
    	}
    }
    

    Python

    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        署名付き URL を使用して OSS にオブジェクトをアップロードします。
    
        :param signed_url: 署名付き URL。
        :param file_path: アップロードするローカルファイルの完全なパス。
        :param headers: オプション。 リクエストヘッダーを指定します。
        :param metadata: ユーザーメタデータ。 このパラメーターはオプションです。
        :return: なし
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # メタデータキーに x-oss-meta- プレフィックスを追加します。
        for key, value in metadata.items():
            headers[f'x-oss-meta-{key}'] = value
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"ステータスコード: {response.status_code}")
                if response.status_code == 200:
                    print("オブジェクトはネットワークライブラリを使用してアップロードされます")
                else:
                    print("アップロードに失敗しました")
                print(response.text)
        except Exception as e:
            print(f"エラーが発生しました: {e}")
    
    if __name__ == "__main__":
        # 署名付き URL に置き換えます。
        signed_url = ""
       
        # ローカルファイルの完全なパスを指定します。 デフォルトでは、ローカルファイルの完全なパスを指定しない場合、スクリプトが保存されているディレクトリからローカルファイルがアップロードされます。
        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: ${response.status}`);
            if (response.status === 200) {
                console.log("The object is uploaded by using the network library");
            } else {
                console.log("Upload failed");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // メイン関数を指定します
    (async () => {
        //  を署名付き URL に置き換えます。
        const signedUrl = "";
    
        // ローカルファイルの完全なパスを指定します。デフォルトでは、ローカルファイルの完全なパスを指定しない場合、ローカルファイルはスクリプトが保存されているディレクトリからアップロードされます。
        const filePath = "C:\\Users\\demo.txt";
    
        // リクエストヘッダーを指定します。リクエストヘッダーの値が、署名付き URL が生成されたときに指定された値と同じであることを確認してください。
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // ユーザーメタデータを指定します。ユーザーメタデータが、署名付き URL が生成されたときのユーザーメタデータと同じであることを確認してください。
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    重要

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

    C++

    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    #include <map>
    #include <string>
    
    // HTTP 応答を処理するために使用されるコールバック関数
    size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append((char*)contents, totalSize);
        return totalSize;
    }
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) {
        CURL* curl;
        CURLcode res;
        std::string readBuffer;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // 署名付き URL を指定します
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // リクエストメソッドを PUT に設定します
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // ローカルファイルを開きます
            FILE* file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Unable to open the local file: " << filePath << std::endl;
                return;
            }
    
            // ローカルファイルのサイズを指定します
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // ファイル読み取りコールバックを設定します
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // リクエストヘッダーを指定します
            struct curl_slist* chunk = nullptr;
            for (const auto& header : headers) {
                std::string headerStr = header.first + ": " + header.second;
                chunk = curl_slist_append(chunk, headerStr.c_str());
            }
            for (const auto& meta : metadata) {
                std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second;
                chunk = curl_slist_append(chunk, metaStr.c_str());
            }
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    
            // 応答を処理するために使用されるコールバック関数を指定します
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
    
            // リクエストを実行します
            res = curl_easy_perform(curl);
    
            // 応答を確認します
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "Upload status code: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "The object is uploaded by using the network library." << std::endl;
                } else {
                    std::cout << "Upload failed." << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // クリーンアップ
            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;
    }
    

    C

    std::string や <iostream>/<fstream> に依存し、C++ コンパイラを必要とする C++ の例とは異なり、次の例は、標準の C ツールチェーンでコンパイルおよび実行できるように、char*、<stdio.h>、および libcurl を使用して標準 C で記述されています。

    #include <stdio.h>
    #include <stdlib.h>
    #include <curl/curl.h>
    
    void upload_file(const char *signed_url, const char *file_path) {
        CURL *curl;
        CURLcode res;
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
        if (curl) {
            curl_easy_setopt(curl, CURLOPT_URL, signed_url);
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
            FILE *file = fopen(file_path, "rb");
            if (!file) {
                fprintf(stderr, "Failed to open file: %s\n", file_path);
                return;
            }
            fseek(file, 0, SEEK_END);
            long file_size = ftell(file);
            fseek(file, 0, SEEK_SET);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_size);
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            res = curl_easy_perform(curl);
            if (res != CURLE_OK)
                fprintf(stderr, "Upload failed: %s\n", curl_easy_strerror(res));
            else {
                long http_code = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
                printf("HTTP status code: %ld\n", http_code);
            }
            fclose(file);
            curl_easy_cleanup(curl);
        }
        curl_global_cleanup();
    }
    
    int main(int argc, char *argv[]) {
        if (argc != 3) {
            printf("Usage: %s <presigned URL> <file path>\n", argv[0]);
            return 1;
        }
        upload_file(argv[1], argv[2]);
        return 0;
    }
    

    コンパイルして実行:

    gcc -o oss_upload oss_upload.c -lcurl
    ./oss_upload <presigned URL> <file path>
    

    このプログラムは、file_path にあるローカルファイルのサイズを読み取り、libcurl を使用してそのサイズを PUT リクエストの本文として signed_url に送信し、返された HTTP ステータスコードを出力します (200 はアップロードが成功したことを示します)。

    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, "Upload status code: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "The object is uploaded by using the network library");
                    } else {
                        Log.d(TAG, "Upload failed");
                    }
    
                    InputStream is = connection.getInputStream();
                    byte[] responseBuffer = new byte[1024];
                    StringBuilder responseStringBuilder = new StringBuilder();
                    while ((count = is.read(responseBuffer)) != -1) {
                        responseStringBuilder.append(new String(responseBuffer, 0, count));
                    }
                    Log.d(TAG, responseStringBuilder.toString());
    
                    return responseCode;
                } catch (IOException e) {
                    e.printStackTrace();
                    return -1;
                }
            }
    
            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
                if (result == 200) {
                    Toast.makeText(SignUrlUploadActivity.this, "Object uploaded", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Upload failed", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

アップロードコールバックの設定

オブジェクトをアップロードする際、署名付き URL にコールバックパラメーターを含めることで、アップロード完了時にアプリケーションサーバーに自動的に通知できます。コールバックの仕組みの詳細については、「コールバック」をご参照ください。

  1. オブジェクトの所有者は、必要なアップロードコールバックパラメーターを含む署名付き URL (PUT メソッドを使用) を生成します。

    Python

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # コマンドライン引数パーサーを作成し、スクリプトの目的を説明します: オブジェクトの署名付き PUT リクエスト URL を生成する (Presign Put Object)。
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # 必須のリージョン、バケット名、エンドポイント、オブジェクトキーを含むコマンドライン引数を定義します。
    parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
    parser.add_argument('--bucket', help='The name of the bucket.', required=True)
    parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
    parser.add_argument('--key', help='The name of the object.', 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
    
        # カスタムエンドポイントが指定されている場合は、設定オブジェクトのエンドポイントプロパティを更新します。
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # 上記の設定で OSS クライアントを初期化し、OSS と対話します。
        client = oss.Client(cfg)
    
        # 指定されたオブジェクトの署名付き PUT リクエストを生成するリクエストを送信します。
        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)) # 有効期限を秒単位で設定します。ここでは 3600 秒に設定されています。
    
    
        # リンクの有効性を確認するために、署名付きリクエストのメソッド、有効期限、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()  # スクリプトのエントリポイント。プログラムのフローはここから始まります。

    Go

    package main
    
    import (
    	"context"
    	"encoding/base64"
    	"encoding/json"
    	"flag"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // グローバル変数を定義します。
    var (
    	region     string // バケットが配置されているリージョン。
    	bucketName string // バケットの名前。
    	objectName string // オブジェクトの名前。
    )
    
    // init 関数を定義して、コマンドラインパラメーターを初期化します。
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	// コマンドラインパラメーターを解析します。
    	flag.Parse()
    
    	// バケット名が空かどうかを確認します。
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, bucket name required")
    	}
    
    	// リージョンが空かどうかを確認します。
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// オブジェクト名が空かどうかを確認します。
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, object name required")
    	}
    
    	// デフォルト設定をロードし、認証情報プロバイダーとリージョンを指定します。
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// OSS クライアントを作成します。
    	client := oss.NewClient(cfg)
    
    	// コールバックパラメーターを指定します。
    	callbackMap := map[string]string{
    		"callbackUrl":      "http://example.com:23450",                                                                   // コールバックサーバーの URL を指定します。例: https://example.com:23450
    		"callbackBody":     "bucket=${bucket}&object=${object}&size=${size}&my_var_1=${x:my_var1}&my_var_2=${x:my_var2}", // コールバックリクエストボディを指定します。
    		"callbackBodyType": "application/x-www-form-urlencoded",                                                          // コールバックリクエストボディの Content-Type を指定します。
    	}
    
    	// コールバックパラメーター設定を JSON 文字列に変換し、Base64 エンコードしてコールバック設定を渡します。
    	callbackStr, err := json.Marshal(callbackMap)
    	if err != nil {
    		log.Fatalf("failed to marshal callback map: %v", err)
    	}
    	callbackBase64 := base64.StdEncoding.EncodeToString(callbackStr)
    
    	callbackVarMap := map[string]string{}
    	callbackVarMap["x:my_var1"] = "thi is var 1"
    	callbackVarMap["x:my_var2"] = "thi is var 2"
    	callbackVarStr, err := json.Marshal(callbackVarMap)
    	if err != nil {
    		log.Fatalf("failed to marshal callback var: %v", err)
    	}
    	callbackVarBase64 := base64.StdEncoding.EncodeToString(callbackVarStr)
    
    	// PutObject メソッドで署名付き URL を生成します。
    	result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
    		Bucket:      oss.Ptr(bucketName),
    		Key:         oss.Ptr(objectName),
    		Callback:    oss.Ptr(callbackBase64),    // コールバックパラメーターを指定します。これは Base64 エンコードされた JSON 文字列です。
    		CallbackVar: oss.Ptr(callbackVarBase64), // カスタムコールバックパラメーターを指定します。これは Base64 エンコードされた JSON 文字列です。
    	},
    		oss.PresignExpires(10*time.Minute),
    	)
    	if err != nil {
    		log.Fatalf("failed to put object presign %v", err)
    	}
    
    	log.Printf("request method:%v\n", result.Method)
    	log.Printf("request expiration:%v\n", result.Expiration)
    	log.Printf("request url:%v\n", result.URL)
    	if len(result.SignedHeaders) > 0 {
    // 応答に署名ヘッダーが含まれている場合、署名付き URL で PUT リクエストを送信する際には、対応するリクエストヘッダーを設定する必要があります。
    		log.Printf("signed headers:\n")
    		for k, v := range result.SignedHeaders {
    			log.Printf("%v: %v\n", k, v)
    		}
    	}
    }
    

    Java

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    
    import java.net.URL;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class OssPresignExample {
        public static void main(String[] args) throws Throwable {
            // この例では、中国 (杭州) リージョンのパブリックエンドポイントを使用します。実際のエンドポイントを指定してください。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // バケット名を指定します。例: examplebucket
            String bucketName = "examplebucket";
            // オブジェクトの完全なパスを指定します。例: exampleobject.txt。オブジェクトの完全なパスにバケット名を含めることはできません。
            String objectName = "exampleobject.txt";
            // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
            String region = "cn-hangzhou";
    
            // OSSClient インスタンスを作成します。
            // OSSClient インスタンスが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            URL signedUrl = null;
            try {
                // コールバックパラメーターを構築します。
                String callbackUrl = "http://www.example.com/callback";
                String callbackBody = "{\"callbackUrl\":\"" + callbackUrl + "\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}";
                String callbackBase64 = Base64.getEncoder().encodeToString(callbackBody.getBytes());
    
                String callbackVarJson = "{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}";
                String callbackVarBase64 = Base64.getEncoder().encodeToString(callbackVarJson.getBytes());
                // リクエストヘッダーを設定します。
                Map<String, String> headers = new HashMap<String, String>();
                // CALLBACK を指定します。
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64);
                // CALLBACK-VAR を指定します。
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64);
    
                // 有効期限を設定します (3600 秒後)。
                Date expiration = new Date(new Date().getTime() + 3600 * 1000);
    
                // 有効期限をフォーマットします。
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                String expirationStr = dateFormat.format(expiration);
    
                // リクエストを構築します。
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
                request.setMethod(HttpMethod.PUT);
                request.setExpiration(expiration);
                // リクエストにリクエストヘッダーを追加します。
                request.setHeaders(headers);
    
                // コールバックと callback-var パラメーターを出力します。
                System.out.println("callback:"+callbackBase64);
                System.out.println("callback-var:"+callbackVarBase64);
    
                // 署名付き URL を生成します。
                URL url = ossClient.generatePresignedUrl(request);
    
                // 結果を出力します。
                System.out.println("method: PUT,");
                System.out.println(" expiration: " + expirationStr + ",");
                System.out.println(" url: " + url);
    
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            }
        }
    }

    PHP

    <?php
    
    // autoload ファイルをインクルードして、必要な依存関係をロードできるようにします。
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // コマンドライン引数の説明を指定します。
    $optsdesc = [
        "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // (必須) バケットが配置されているリージョンを指定します。
        "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // (オプション) 他のサービスが OSS にアクセスするために使用できるエンドポイントを指定します。
        "bucket" => ['help' => 'The name of the bucket', 'required' => True], // (必須) バケットの名前を指定します。
        "key" => ['help' => 'The name of the object', 'required' => True], // (必須) オブジェクトの名前を指定します。
    ];
    
    // 説明を getopt で必要な長いオプションのリストに変換します。
    // 各パラメーターの末尾にコロン (:) を追加して、値が必要であることを示します。
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // コマンドラインパラメーターを解析します。
    $options = getopt("", $longopts);
    
    // 必須パラメーターが提供されているかどうかを確認します。
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // パラメーターのヘルプ情報を取得します
            echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
            exit(1); // 必須パラメーターが設定されていない場合はプログラムを終了します。
        }
    }
    
    // 解析されたパラメーターから値を取得します。
    $region = $options["region"]; // バケットが配置されているリージョン
    $bucket = $options["bucket"]; // バケットの名前
    $key = $options["key"];       // オブジェクトの名前
    
    // 環境変数からアクセス認証情報をロードします。
    // EnvironmentVariableCredentialsProvider を使用して、環境変数から AccessKey ID と AccessKey シークレットを取得します。
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // SDK のデフォルト設定を使用します。
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // 認証情報プロバイダーを設定します
    $cfg->setRegion($region); // バケットが配置されているリージョンを設定します
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // 提供されている場合はエンドポイントを設定します
    }
    
    // OSS クライアントインスタンスを作成します。
    $client = new Oss\Client($cfg);
    
    // x-oss-callback および x-oss-callback-var ヘッダーを追加します
    // Webhook アドレスを定義します
    $call_back_url = "http://www.example.com/callback";
    
    // コールバックパラメーターを構築します: Webhook アドレスとリクエストボディを指定し、Base64 エンコーディングを使用します
    // プレースホルダー {var1} と {var2} を使用して ${x:var1} と ${x:var2} を置き換えます
    $callback_body_template = "bucket={bucket}&object={object}&my_var_1={var1}&my_var_2={var2}";
    $callback_body_replaced = str_replace(
        ['{bucket}', '{object}', '{var1}', '{var2}'],
        [$bucket, $key, 'value1', 'value2'],
        $callback_body_template
    );
    $callback = base64_encode(json_encode([
        "callbackUrl" => $call_back_url,
        "callbackBody" => $callback_body_replaced
    ]));
    
    // Base64 エンコーディングを使用してカスタム変数 (callback-var) を構築します
    $callback_var = base64_encode(json_encode([
        "x:var1" => "value1",
        "x:var2" => "value2"
    ]));
    
    // オブジェクトをアップロードするための PutObjectRequest オブジェクトを作成します。
    // 注: contentType、metadata、および headers パラメーターは、署名計算のためにここに追加されます。
    $request = new Oss\Models\PutObjectRequest(
        bucket: $bucket,
        key: $key,
        callback:$callback,
        callbackVar:$callback_var,
    );
    
    // presign メソッドを呼び出して署名付き URL を生成します。
    $result = $client->presign($request);
    
    // 署名付きの結果を出力し、ユーザーがオブジェクトを直接アップロードするために使用できる署名付き URL を出力します
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL .
        'put object url:' . $result->url . PHP_EOL
    );
    
  2. 他のユーザーは、PUT メソッドを使用して署名付き URL を使用してオブジェクトをアップロードします。

    curl

    curl -X PUT -T /path/to/local/file "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"

    Java

    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.entity.FileEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.net.URL;
    import java.util.*;
    
    public class SignUrlUpload {
        public static void main(String[] args) throws Throwable {
            CloseableHttpClient httpClient = null;
            CloseableHttpResponse response = null;
    
            // <signedUrl> を認証済み URL に置き換えます。
            URL signedUrl = new URL("<signedUrl>");
    
            // ローカルファイルの完全なパスを指定します。ローカルパスを指定しない場合、ファイルはデフォルトでサンプルプログラムのプロジェクトパスからアップロードされます。
            String pathName = "C:\\Users\\demo.txt";
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                httpClient = HttpClients.createDefault();
                response = httpClient.execute(put);
    
                System.out.println("Status code returned for the upload:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Upload successful using network library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                 if (response != null) {
                     response.close();
                 }
                 if (httpClient != null) {
                     httpClient.close();
                 }
             }
        }
    }       

    Go

    package main
    
    import (
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl, filePath string) error {
    	// ファイルを開きます。
    	file, err := os.Open(filePath)
    	if err != nil {
    		return fmt.Errorf("Unable to open file: %w", err)
    	}
    	defer file.Close()
    
    	// 新しい HTTP クライアントを作成します。
    	client := &http.Client{}
    
    	// PUT リクエストを作成します。
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("Failed to create request: %w", err)
    	}
    
    	// リクエストを送信します。
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("Failed to send request: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// 応答を読み取ります。
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("Failed to read response: %w", err)
    	}
    
    	fmt.Printf("Status code returned for the upload: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Upload successful using network library.")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// <signedUrl> を認証済み URL に置き換えます。
    	signedUrl := "<signedUrl>"
    
    	// ローカルファイルの完全なパスを指定します。ローカルパスを指定しない場合、ファイルはデフォルトでサンプルプログラムのプロジェクトパスからアップロードされます。
    	filePath := "C:\\Users\\demo.txt"
    
    	err := uploadFile(signedUrl, filePath)
    	if err != nil {
    		fmt.Println("An error occurred:", err)
    	}
    }
    

    python

    import requests
    
    def upload_file(signed_url, file_path):
        try:
            # ファイルを開きます。
            with open(file_path, 'rb') as file:
                # PUT リクエストを送信してファイルをアップロードします。
                response = requests.put(signed_url, data=file)
         
            print(f"アップロードに対して返されたステータスコード: {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

    重要

    Node.js を使用してファイルをアップロードする際に 403 署名不一致エラーが発生した場合、通常はアップロードリクエストで Content-Type リクエストヘッダーが明示的に設定されているが、このヘッダーが署名付き URL の生成時に含まれていなかったことが原因です。この不一致により、署名検証が失敗します。この問題を解決するには、アップロードリクエストで Content-Type リクエストヘッダーを設定しないか、署名付き URL を生成する際に Content-Type リクエストヘッダーを指定します。

    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);
    
            console.log(`Status code returned for the upload: ${response.status}`);
            if (response.status === 200) {
                console.log('Upload successful using network library.');
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // メイン関数。
    (async () => {
        // <signedUrl> を認証済み URL に置き換えます。
        const signedUrl = '<signedUrl>';
        
        // ローカルファイルの完全なパスを指定します。ローカルパスを指定しない場合、ファイルはデフォルトでサンプルプログラムのプロジェクトパスからアップロードされます。
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    重要

    Browser.js を使用してファイルをアップロードする際に 403 署名不一致エラーが発生した場合、通常はブラウザが自動的に 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>File Upload Example</title>
    </head>
    <body>
        <h1>File Upload Example</h1>
    
        <!-- ファイルを選択 -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</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('Please select a file to upload.');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('File uploaded successfully!');
                } catch (error) {
                    console.error('Error during upload:', error);
                    alert('Upload failed: ' + error.message);
                }
            });
    
            /**
             * ファイルを OSS にアップロードします。
             * @param {File} file - アップロードするファイル。
             * @param {string} presignedUrl - 署名付き URL。
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,  // ファイル全体を直接アップロードします。
                });
    
                if (!response.ok) {
                    throw new Error(`Upload failed, status: ${response.status}`);
                }
    
                console.log('File uploaded successfully');
            };
        </script>
    </body>
    </html>

    C#

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

    C++

    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath) {
        CURL *curl;
        CURLcode res;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // URL を設定します。
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // リクエストメソッドを PUT に設定します。
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // ファイルを開きます。
            FILE *file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Unable to open file: " << filePath << std::endl;
                return;
            }
    
            // ファイルサイズを取得します。
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);
    
            // ファイルサイズを設定します。
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // 入力ファイルハンドルを設定します。
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
    
            // リクエストを実行します。
            res = curl_easy_perform(curl);
    
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "Status code returned for the upload: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "Upload successful using network library." << 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 for the upload: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "Upload successful using network library.");
                    }
    
                    return "Upload complete. Status code: " + responseCode;
    
                } catch (IOException e) {
                    e.printStackTrace();
                    return "Upload failed: " + e.getMessage();
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
    
            @Override
            protected void onPostExecute(String result) {
                Log.d(TAG, result);
            }
        }
    
        public static void main(String[] args) {
            SignUrlUploadActivity activity = new SignUrlUploadActivity();
            // <signedUrl> を認証済み URL に置き換えます。
            String signedUrl = "<signedUrl>";
            // ローカルファイルの完全なパスを指定します。ローカルパスを指定しない場合、ファイルはデフォルトでサンプルプログラムのプロジェクトパスからアップロードされます。
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

追加情報

署名付き URL とは

事前署名付き URL は、OSS 内の特定のオブジェクトへの一時的なアクセスを許可する、時間制限のある安全なリンクです。事前署名付き URL を生成するために、クライアントは AccessKey ペア、リソースパス、および有効期限を使用して暗号署名を作成します。この署名は元の URL に追加され、時間制限のあるアクセスリンクが生成されます。事前署名付き URL の一般的なフォーマットは https://BucketName.Endpoint/Object?Signature です。

第三者が署名付き URL にアクセスすると、OSS は署名を検証します。署名が無効または期限切れの場合、アクセスは拒否されます。

署名付き URL の例:

https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-process=image%2Fresize%2Cp_10&x-oss-date=20241115T095058Z&x-oss-expires=3600&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241115%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=6e7a********************************

この方法により、オブジェクトの所有者は、プライベートキーを公開することなく、第三者に限定的なアクセスを安全に提供できます。

適用シナリオ

  • 一時的なオブジェクト共有:第三者が特定のオブジェクトを安全にアップロードまたはダウンロードできるようにするために、バックエンドは時間制限のある署名付き URL を生成し、それをフロントエンドに提供します。第三者はこの URL を使用して、許可された時間内に操作を実行でき、制御された安全なデータアクセスが保証されます。

  • 柔軟なオブジェクト共有:オブジェクトの所有者は、署名付き URL を生成し、電子メールやメッセージングアプリを介して第三者に配布することで、オブジェクトを安全に共有できます。受信者は、URL をブラウザに貼り付けるだけで、目的のオブジェクトをダウンロードできます。

よくある質問

アップロードアクセスのみに制限するのではなく、OSS リソースに対してより広範な権限を他のユーザーに付与するにはどうすればよいですか?

署名付き URL に加えて、OSS はより柔軟な一時的な権限付与方法である STS の一時的なアクセス認証情報を提供しています。特定のアクションに限定される署名付き URL とは異なり、STS 認証情報を使用すると、第三者は、オブジェクトのリスト表示、コピー、削除など、より広範な操作を時間制限付きの権限で実行できます。詳細については、「STS の一時的なアクセス認証情報を使用した OSS へのアクセス」をご参照ください。

特定のウェブサイトからのリクエストのみを許可し、その他すべてをブロックするようにオブジェクトへのアクセスを制限できますか?

はい、Referer ベースのホットリンク保護を有効にするには、ホワイトリストを設定して OSS リソースへのアクセスを制限できます。これにより、承認されたウェブサイト (自社サイトなど) のみがリソースにアクセスできるようになり、承認されていないソースや悪意のあるソースからの直接リクエストがブロックされます。詳細については、「Referer ホワイトリストまたはブラックリストを設定して、他のウェブサイトが OSS オブジェクトにリンクするのを防ぐ」をご参照ください。

ブラウザに CORS エラーが表示されるのはなぜですか?また、そのトラブルシューティング方法を教えてください。

バケットにオリジン間リソース共有 (CORS) ポリシーが設定されていないか、現在の CORS 設定が正しくありません。「CORS」を参照して、設定を確認および調整してください。

ブラウザに「405 Method Not Allowed」エラーが表示されるのはなぜですか?また、そのトラブルシューティング方法を教えてください。

リクエストメソッドが正しくありません。署名付き URL を使用してオブジェクトをアップロードする場合は、POST メソッドではなく PUT メソッドを使用してください。

アップロードボディとして URL を渡すと、OSS が実際のファイルではなく URL 文字列を保存するのはなぜですか?

署名付き URL を使用してデータをアップロードする場合、署名付き URL のメカニズムはクライアントから OSS への直接のアップロードチャネルです。OSS は PUT リクエストボディの生のバイトをオブジェクトとして保存します。ボディを URL として解釈したり、代理で外部アドレスからコンテンツを取得したりすることはありません。

URL 文字列 (たとえば、https://example.com/video.mp4) を PUT リクエストボディとして渡した場合、OSS はその URL 文字列をオブジェクトのコンテンツとして保存します。たとえば、66 バイトの URL 文字列は、そのアドレスにあるファイルではなく、URL テキストのみを含む 66 バイトのオブジェクトになります。

外部 URL でホストされているファイルを OSS バケットに保存するには、サーバーがまずファイルデータをダウンロードし、次に PutObject またはマルチパートアップロードを使用して実際のバイトを OSS にアップロードする必要があります。次の Python の例は、このサーバーサイドリレーを実装する方法を示しています:

import requests
import alibabacloud_oss_v2 as oss

def relay_url_to_oss(external_url, bucket_name, object_key, region):
    # ステップ 1: 外部 URL からファイルをダウンロードします。
    response = requests.get(external_url, stream=True)
    response.raise_for_status()
    file_content = response.content

    # ステップ 2: OSS クライアントを設定します。
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = region
    client = oss.Client(cfg)

    # ステップ 3: ダウンロードしたデータを OSS にアップロードします。
    result = client.put_object(oss.PutObjectRequest(
        bucket=bucket_name,
        key=object_key,
        body=file_content,
    ))
    print(f"Upload successful. ETag: {result.etag}")

# 使用例
relay_url_to_oss(
    external_url="https://example.com/sample.jpg",
    bucket_name="examplebucket",
    object_key="sample.jpg",
    region="cn-hangzhou"
)