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

Object Storage Service:クライアントからOSSに直接オブジェクトをアップロードする

最終更新日:Mar 11, 2024

ダイレクトアップロードを使用すると、クライアントからObject Storage Service (OSS) にデータを直接アップロードできます。 ダイレクトアップロードソリューションは、アプリケーションサーバーとの間でオブジェクトを転送する必要をなくすことにより、アップロードを高速化し、アプリケーションサーバーのリソース使用量を削減します。 このトピックでは、このソリューションの利点、実装方法、およびベストプラクティスについて説明します。

メリット

従来のサーバーおよびクライアントアーキテクチャでは、アプリケーションサーバーからOSSにデータをアップロードするのが一般的なアップロード方法です。 クライアントはオブジェクトをアプリケーションサーバーにアップロードし、アプリケーションサーバーはオブジェクトをOSSにアップロードします。 アップロードプロセス中、データはネットワーク経由で2回転送する必要があります。 これは、ネットワークリソースの浪費及びアプリケーションサーバのリソース使用の増加をもたらす。 この問題を解決するには、オブジェクトをアプリケーションサーバーにアップロードせずに、オブジェクトをOSSに直接アップロードします。

image

実装方法

クライアントからOSSに直接データをアップロードするには、次の問題を解決する必要があります。

CORS

クライアントがwebクライアントまたはミニプログラムの場合、クロスオリジンリソース共有 (CORS) を許可する必要があります。 データのセキュリティを確保するために、ブラウザとミニプログラムは通常CORSを禁止します。 これにより、クライアントコードを使用してOSSに接続できなくなります。 OSSバケットのCORSルールを設定して、webクライアントまたはミニプログラムのドメイン名がOSSにアクセスできるようにすることができます。 CORSルールの設定方法の詳細については、「CORS」をご参照ください。

セキュリティ権限付与

オブジェクトをOSSにアップロードするには、RAMユーザーのAccessKeyペアを使用して署名認証を完了する必要があります。 クライアントが永続的なAccessKeyペアを使用している場合、AccessKeyペアが漏洩する可能性があります。 これは、セキュリティリスクを引き起こす可能性があります。 この問題を解決するには、次のいずれかのソリューションを使用して安全なアップロードを実装します。

  • アプリケーションサーバーのSTSから一時的なアクセス資格情報を取得

    ほとんどのオブジェクトアップロードのシナリオでは、Security Token Service (STS) SDKを使用してアプリケーションサーバーの一時的なアクセス資格情報を取得し、一時的なアクセス資格情報とOSS SDKを使用してクライアントからOSSに直接オブジェクトをアップロードすることを推奨します。 クライアントは、アプリケーションサーバ上の一時的なアクセス資格情報を再利用して署名を生成することができる。 これは、マルチパートアップロードと再開可能アップロードを使用してラージオブジェクトをアップロードするシナリオに適しています。 ただし、STSへの頻繁な呼び出しにより、スロットリングが発生する場合があります。 この場合、一時的なアクセス資格情報をキャッシュし、有効期間が終了する前に更新することを推奨します。 詳細については、「STSの概要」をご参照ください。

  • アプリケーションサーバーからPostObjectの署名とPOSTポリシーを取得する

    アップロードするオブジェクトの属性を制限するシナリオでは、PostObject操作を呼び出すために必要な情報をアプリケーションサーバーから取得する必要があります。 必要な情報には、署名とPOSTポリシーが含まれます。 クライアントは、取得した情報を使用して、OSS SDKを使用せずにオブジェクトをOSSに直接アップロードできます。 サーバーによって生成されたポリシーを使用して、オブジェクトのサイズやタイプなど、アップロードできるオブジェクトの属性を制限できます。 このソリューションは、HTMLフォームを使用したオブジェクトのアップロードに適しています。 このソリューションは、マルチパートアップロードと再開可能アップロードをサポートしていません。 詳細は、「PostObject」をご参照ください。

  • アプリケーションサーバーからPutObjectの署名付きURLを取得

    単純なオブジェクトアップロードのシナリオでは、アプリケーションサーバーでOSS SDKを使用して、PutObject操作を呼び出すために必要な署名付きURLを取得できます。 その後、クライアントは署名付きURLを使用して、OSS SDKを使用せずにオブジェクトをアップロードできます。 このソリューションは、マルチパートアップロードと再開可能アップロードには適していません。 アプリケーションサーバは、各部分の署名付きURLを生成し、署名付きURLをクライアントに返す。 これは、アプリケーションサーバとの対話の数およびネットワーク要求の複雑さを増大させる。 さらに、クライアントは、部分の内容または順序を修正することができ、その結果、無効な結合オブジェクトが生じる。 詳細については、「署名V1を使用した署名付きURLの作成」をご参照ください。

アプリケーションサーバーのSTSから一時的なアクセス資格情報を取得する

次の図は、アプリケーションサーバーから返されたSTSの一時的なアクセス資格情報を使用して、クライアントからオブジェクトをOSSにアップロードする方法を示しています。

image
  1. クライアントは、アプリケーションサーバーに一時的なアクセス資格情報を要求します。

  2. アプリケーションサーバーはSTS SDKを使用してAssumeRole操作を呼び出し、一時的なアクセス資格情報を取得します。

  3. STSは一時的なアクセス資格情報を生成してアプリケーションサーバーに返します。

  4. アプリケーションサーバーは、一時的なアクセス資格情報をクライアントに返します。

  5. クライアントは、OSS SDKを使用して、一時的なアクセス資格情報を使用してオブジェクトをOSSにアップロードします。

  6. OSSは成功応答をクライアントに返します。

デモプロジェクト

sts.zip

サーバー側のサンプルコード

次のサンプルコードは、アプリケーションサーバーがSTSから一時的なアクセス資格情報を取得する方法の例を示しています。

import json
alibabacloud_tea_openapi.modelsからのインポートConfig
alibabacloud_sts20150401.clientからSts20150401Clientとしてのインポートクライアント
alibabacloud_sts20150401からモデルをsts_20150401_modelsとしてインポートする
alibabacloud_credentials.clientからCredentialClientとしてのインポートクライアント

# <YOUR_ROLE_ARN> を、オブジェクトをOSSバケットにアップロードする権限を持つRAMロールのAlibaba Cloud Resource Name (ARN) に置き換えます。 
role_arn_for_oss_upload = '<YOUR_ROLE_ARN>'
# <YOUR_REGION_ID> をSTSサービスのリージョンのIDに置き換えます。 例:cn-hangzhou。 
region_id = '<YOUR_REGION_ID>'

def get_sts_token():
    # CredentialClientの初期化時にパラメーターを指定しない場合、デフォルトの資格情報チェーンが使用されます。 
    # ローカルコンピューターでプログラムを実行する場合は、環境変数と環境変数を設定してAccessKeyペアを指定できます。
    # Elastic Compute Service (ECS) インスタンス、elasticコンテナインスタンス、またはcontainer Service for Kubernetes (ACK) クラスター内のノードでプログラムを実行する場合、ALIBABA_CLOUECS_METADATA環境変数を設定することで、バインドされたインスタンスまたはノードを指定できます。 SDKは、STSから取得した一時的なアクセス資格情報を自動的に交換します。 
    config = Config(region_id=region_id, credential=CredentialClient())
    sts_client = Sts20150401Client(config=config)
    assume_role_request = sts_20150401_models.AssumeRoleRequest (
        role_arn=role_arn_for_oss_upload、
        # <YOUR_ROLE_SESSION_NAME> をoss-role-sessionなどのカスタムセッション名に置き換えます。 
        role_session_name='<YOUR_ROLE_SESSION_NAME>'
    )
    response = sts_client.assume_role(assume_role_request)
    token = json.dumps(response.body.credentials.to_map())
    リターントークン 

クライアント側のサンプルコード

次のサンプルコードは、一時的なアクセス資格情報を使用して、webクライアントからオブジェクトをOSSにアップロードする方法の例を示しています。

let credentials = null;
const form = document.querySelector("form");
form.addEventListener("submit", async (event) => {
  event.preventDefault();
  // 有効期限が切れた場合にのみ、一時的なアクセス資格情報を再度取得します。 これにより、STSへの呼び出し数が減少します。 
  if (isCredentialsExpired (資格情報)) {
    const応答=await fetch("/get_sts_token_for_oss_upload", {
      メソッド: "GET" 、
    });
    credentials = await response.json();
  }
  const client = new OSS({
    // <YOUR_BUCKET> をOSSバケットの名前に置き換えます。 
    bucket: "<YOUR_BUCKET>" 、
    // <YOUR_REGION> を、OSSバケットが配置されているリージョンのIDに置き換えます。 例: oss-cn-hangzhou. 
    region: "oss-<YOUR_REGION>" 、
    accessKeyId: 認証情報。AccessKeyId、
    accessKeySecret: 認証情報。AccessKeySecret,
    stsToken: 資格情報。SecurityToken、
  });

  const fileInput = document.querySelector("#file");
  const file = fileInput.files[0];
  const result = await client.pu t(file.name、ファイル);
  console.log (結果);
});

/**
 * 一時アクセス資格情報の有効期限が切れるかどうかを判断します。 
 **/
関数isCredentialsExpired (資格情報) {
  if (! 資格情報) {
    return true;
  }
  const expireDate = new Date(credentials.Expiration);
  const now = new Date();
  // 一時的なアクセス資格情報の残りの有効期間が1分未満の場合、一時的なアクセス資格情報は期限切れと見なされます。 
  を返すexpireDate.getTime() - now.getTime() <= 60000;
} 

アプリケーションサーバーからPostObjectの署名とPOSTポリシーを取得する

次の図は、アプリケーションサーバーから取得した署名とPOSTポリシーを使用して、クライアントからOSSにオブジェクトをアップロードする方法を示しています。

image
  1. クライアントは、署名やPOSTポリシーなどの情報をアプリケーションサーバーに要求します。

  2. アプリケーションサーバーは、署名やPOSTポリシーなどの情報を生成してクライアントに返します。

  3. クライアントは、署名やPOSTポリシーなどの情報を使用してPostObject操作を呼び出し、HTMLフォームを使用してオブジェクトをOSSにアップロードします。

  4. OSSは成功応答をクライアントに返します。

デモプロジェクト

postsignature.zip

サーバー側のサンプルコード

次のサンプルコードは、アプリケーションサーバーから署名とPOSTポリシーを取得する方法の例を示しています。

osのインポート
hashlibからsha1をshaとしてインポート
jsonのインポート
インポートbase64
hmacのインポート
datetimeのインポート
インポート時間

# OSS_ACCESS_KEY_ID環境変数を設定します。 
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID ')
# OSS_ACCESS_KEY_SECRET環境変数を設定します。 
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET ')
# <YOUR_BUCKET> をバケットの名前に置き換えます。 
bucket = '<YOUR_BUCKET>'
# ホストをBucketName.Endpoint形式の値に設定します。 <YOUR_BUCKET> をバケットの名前に置き換えます。 <YOUR_ENDPOINT> を、バケットが配置されているリージョンのエンドポイントに置き換えます。 
host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
# OSSにアップロードするオブジェクトの名前にプレフィックスを指定します。 
upload_dir = 'user-dir-prefix/'
# 有効期間を指定します。 単位は秒です。 
expire_time = 3600


def generate_expailation (秒):
    """
    有効期限は、指定された有効期間に基づいて計算されます。 単位は秒です。 
    : param seconds: 有効期間 (秒) 。 
    : return: ISO 8601標準の時間文字列。 例: 2014-12-01T12:00:00.000Z 
    """
    now = int(time.time())
    expiration_time = now + 秒
    gmt = datetime.datetime.utcfromtimestamp(expiration_time). isofformat ()
    gmt += 'Z'
    gmtを返す


def generate_signature(access_key_secret、有効期限、条件、policy_extra_props=なし):
    """
    署名文字列を生成します。 
    : param access_key_secret: バケットへのアクセス権限を持つAccessKeyシークレット。 
    : param expiration: 署名の有効期限が切れる時刻。 時刻を ISO 8601 規格 (yyyy-MM-ddTHH:mm:ssZ) の形式で指定します。 例: 2014-12-01T12:00:00.000Z 
    : param条件: フォームのアップロード時に指定できる値を制限するために使用できるポリシー条件。 
    : param policy_extra_props: 追加のポリシーパラメーター。 追加のパラメータをdictとして渡すことができます。 
    : return: 署名文字列。 
    """
    policy_dict = {
        'expiration': 有効期限、
        'conditions': 条件
    }
    policy_extra_propsがNoneでない場合:
        policy_dict.update(policy_extra_props)
    policy = json.dumps(policy_dict).strip()
    policy_encode = base64.b64encode(policy.encode())
    h = hmac.new(access_key_secret.encode(), policy_encode, sha)
    sign_result = base64.b64encode(h.digest()).strip()
    リターンsign_result.decode()

def generate_upload_params():
    policy = {
        # ポリシーの有効期間を指定します。 
        "expailation": generate_expailation (expire_time) 、
        # ポリシー条件を指定します。 
        "conditions": [
            # success_action_redirectが指定されていない場合、オブジェクトのアップロード後にHTTPステータスコード204が返されます。 
            ["eq" 、"$success_action_status" 、"200"] 、
            # フォームフィールドの値は、指定されたプレフィックスで始まる必要があります。 たとえば、キーフォームフィールドの値がuser/user1で始まる場合、条件は ["starts-with", "$key", "user/user1"] です。 
            ["starts-with" 、"$key" 、upload_dir] 、
            # アップロードできるオブジェクトの最小サイズと最大サイズを指定します。 単位:バイト 
            ["content-length-range", 1, 1000000],
            # アップロードするオブジェクトのタイプを指定したイメージタイプに設定します。
            ["in", "$content-type", ["image/jpg", "image/png"]]
        ]
    }
    signature = generate_signature(access_key_secret, policy.get('expiration'), policy.get('conditions'))
    response = {
        'policy': base64.b64encode(json.dumps(policy).encode('utf-8 ')).decode() 、
        'ossAccessKeyId': access_key_id、
        'signature': signature、
        'host ': ホスト、
        'dir': upload_dir
        # 追加のパラメーターを指定します。
    }
    を返すjson.dumps (応答) 

クライアント側のサンプルコード

次のサンプルコードは、署名とPOSTポリシーを使用してwebクライアントからOSSにオブジェクトをアップロードする方法の例を示しています。

const form = document.querySelector('form');
const fileInput = document.querySelector('#file');
form.addEventListener('submit', (event) => {
  event.preventDefault();
  let file = fileInput.files[0];
  let filename = fileInput.files[0].name;
  fetch('/get_post_signature_for_oss_upload', { method: 'GET' })
    . then(response => response.json())
    . その後 (data => {
      const formData=新しいFormData();
      formData.append('name',filename);
      formData.append('policy', data.policy);
      formData.append('OSSAccessKeyId', data.ossAccessKeyId);
      formData.append('success_action_status '、'200');
      formData.append('signature', data.signature);
      formData.append('key ', data.dir + filename);
      // fileは最後のフォームフィールドでなければなりません。 他のフォームフィールドに特別な注文は必要ありません。 
      formData.append('file' 、ファイル);
      fetch(data.host, { method: 'POST', body: formData },).then((res) => {
        console.log(res);
        alert ('Object Uploaded');
      });
    })
    . catch(error => {
      console.log('OSSアップロードパラメータの取得中にエラーが発生しました:' 、エラー);
    });
});

アプリケーションサーバーからPutObjectの署名付きURLを取得する

次の図は、アプリケーションサーバーから取得した署名付きURLを使用して、クライアントからオブジェクトをOSSにアップロードする方法を示しています。

image
  1. クライアントは、アプリケーションサーバーに署名付きURLを要求します。

  2. アプリケーションサーバーは、OSS SDKを使用してPUTリクエストの署名付きURLを生成し、署名付きURLをクライアントに返します。

  3. クライアントは署名付きURLを使用してPutObject操作を呼び出し、オブジェクトをOSSにアップロードします。

  4. OSSは成功応答をクライアントに返します。

デモプロジェクト

presignedurl.zip

サーバー側のサンプルコード

次のサンプルコードは、アプリケーションサーバーから署名付きURLを取得する方法の例を示しています。

oss2のインポート
oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート

# 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# <YOUR_ENDPOINT> を、バケットが配置されているリージョンのエンドポイントに置き換えます。 たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントをhttps://oss-cn-hangzhou.aliyuncs.comに設定します。 
# <YOUR_BUCKET> をバケットの名前に置き換えます。 
bucket = oss2.Bucket(auth, '<YOUR_ENDPOINT>', '<YOUR_BUCKET>')
# 有効期間を指定します。 単位は秒です。 
expire_time = 3600
# オブジェクトのフルパスを指定します。 例: exampledir/exampleobject.png バケット名をフルパスに含めないでください。 
object_name = 'exampledir/exampleobject.png'

def generate_presigned_url():
    # ヘッダーを指定します。 
    headers = dict()
    # Content-Typeヘッダーを指定します。 
    ヘッダー ['Content-Type'] = 'image/png'
    # ストレージクラスを指定します。 
    # headers["x-oss-storage-class"] = "Standard"
    # デフォルトでは、署名付きURLが生成されると、OSSはオブジェクトのフルパスのスラッシュ (/) をエスケープ文字として識別します。 この場合、署名付きURLを直接使用することはできません。 
    # slash_safeパラメーターをTrueに設定します。 このように、OSSはオブジェクトのフルパスのスラッシュ (/) をエスケープ文字として識別しません。 この場合、生成された署名付きURLを使用してオブジェクトをアップロードできます。 
    url = bucket.sign_url('PUT', object_name, expire_time, slash_safe=True, headers=headers)
    リターンurl 

クライアント側のサンプルコード

次のサンプルコードは、署名付きURLを使用してwebクライアントからOSSにオブジェクトをアップロードする方法の例を示しています。

const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
  event.preventDefault();
  const fileInput = document.querySelector("#file");
  const file = fileInput.files[0];
  fetch('/get_presigned_url_for_oss_upload?filename =${ file.name}', { method: "GET" })
    . then((応答) => {
        return response.text();
     })
    . then((url) => {
      fetch(url, {
        メソッド: "PUT" 、
        headers: 新しいヘッダー ({
          'Content-Type': 'image/png' 、
        }),
        body: ファイル、
       }).then((res) => {
            console.log(res);
            alert ('Object Uploaded');
       });
   });
});

ベストプラクティス

クライアントからOSSにデータをアップロードするためのベストプラクティスについては、以下のトピックを参照してください。