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

Object Storage Service:フォームアップロード

最終更新日:Aug 22, 2024

フォームアップロードを使用すると、webアプリケーションの標準HTMLフォームを使用して、オブジェクトをObject Storage Service (OSS) に直接アップロードできます。 このようにして、フロントエンドページでオブジェクトが選択された後、ブラウザはPostObjectリクエストを開始し、Webサイトサーバーを使用せずにオブジェクトをOSSサーバーに直接アップロードします。 これにより、Webサイトサーバーの作業負荷が軽減され、オブジェクトのアップロードの効率と安定性が向上します。

制限事項

フォームアップロードを使用してアップロードするオブジェクトのサイズは、5 GBを超えることはできません。

シナリオ

フォームのアップロードは、以下のシナリオを含むwebアプリケーションで広く使用されています。

  • ユーザーデータのアップロード: ユーザーは、アカウントを登録するときに、アバター、IDカードの写真、またはその他の身元確認資料をアップロードします。 個人センターの情報を変更するときに、新しいアバターまたは背景画像をアップロードします。

  • オブジェクトの共有とストレージ: ユーザーは、ドキュメント、画像、オーディオファイル、ビデオファイルなどのさまざまな形式のオブジェクトをAlibaba Cloudにアップロードし、オンラインディスクや共同作業プラットフォーム上のフォームを使用してストレージと共有します。

  • コンテンツの作成と公開: ユーザーは、ブログ、フォーラム、Q&Aコミュニティなどのプラットフォームで記事を作成し、フォームを使用してコンテンツサプリメントとして画像や添付ファイルをアップロードします。

  • Eコマース管理: マーチャントは、商品の写真、詳細な説明文書、資格などの情報を、eコマースプラットフォームのバックグラウンドでアップロードします。 消費者は、購入プロセス中に請求書要件またはその他のサポート資料をアップロードします。

  • オンライン教育プラットフォーム: 学生は、ドキュメント、PPT、ビデオファイルなどの宿題やプロジェクトをアップロードします。 教師は教材やコースウェアをアップロードします。

  • 募集ウェブサイト: 求職者は履歴書、ポートフォリオ、その他の資料をアップロードします。 企業は、ポジションを投稿するときに、会社のロゴや採用文書などの資料をアップロードします。

  • アンケートとフィードバック: ユーザーは、オンラインアンケートに記入するときに、追加の証拠または説明文書をアップロードします。

  • ソフトウェア開発コラボレーション: 開発者は、GitHubやGitLabなどのコードホスティングプラットフォームからコードファイルまたはプロジェクトドキュメントをアップロードします。

解決策

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

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

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

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

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

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

手順

  1. サーバーは、署名やPOSTポリシーなどの情報を生成します。

    • サンプルプロジェクト: postsignature.zip

    • 次のサンプルコードは、アプリケーションサーバーがPostObjectの署名とPOSTポリシーを生成する方法の例を示しています。

      説明

      サンプルコードはFunction Computeにデプロイできます。 oss-upload-post-signature-app

      import os
      from hashlib import sha1 as sha
      import json
      import base64
      import hmac
      import datetime
      import time
      
      # Obtain the AccessKey ID from the OSS_ACCESS_KEY_ID environment variable. 
      access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
      # Obtain the AccessKey secret from the OSS_ACCESS_KEY_SECRET environment variable. 
      access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
      # Replace <YOUR_BUCKET> with the name of the bucket. 
      bucket = '<YOUR_BUCKET>'
      # Set host to a value that is in the BucketName.Endpoint format. Replace <YOUR_BUCKET> with the name of the bucket. Replace <YOUR_ENDPOINT> with the endpoint of the region in which the bucket is located, such as oss-cn-hangzhou.aliyuncs.com. 
      host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
      # Specify the prefix in the name of the object that you want to upload to OSS. 
      upload_dir = 'user-dir-prefix/'
      # Specify the validity period. Unit: seconds. 
      expire_time = 3600
      
      
      def generate_expiration(seconds):
          """
          The expiration time is calculated based on the specified validity period. Unit: seconds. 
          :param seconds: the validity period (seconds). 
          :return: the time string in the ISO 8601 standard. Example: 2014-12-01T12:00:00.000Z. 
          """
          now = int(time.time())
          expiration_time = now + seconds
          gmt = datetime.datetime.utcfromtimestamp(expiration_time).isoformat()
          gmt += 'Z'
          return gmt
      
      
      def generate_signature(access_key_secret, expiration, conditions, policy_extra_props=None):
          """
          Generate a signature string. 
          :param access_key_secret: the AccessKey secret that has the permissions to access the bucket. 
          :param expiration: the time when the signature expires. Specify the time in the ISO 8601 standard in the yyyy-MM-ddTHH:mm:ssZ format. Example: 2014-12-01T12:00:00.000Z. 
          :param conditions: the policy conditions that can be used to limit the values that you can specify during form upload. 
          :param policy_extra_props: the additional policy parameters. You can pass additional parameters as a dict. 
          :return: the signature string. 
          """
          policy_dict = {
              'expiration': expiration,
              'conditions': conditions
          }
          if policy_extra_props is not 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()
          return sign_result.decode()
      
      def generate_upload_params():
          policy = {
              # Specify the validity period. 
              "expiration": generate_expiration(expire_time),
              # Specify the policy conditions. 
              "conditions": [
                  # If success_action_redirect is not specified, HTTP status code 204 is returned after the object is uploaded. 
                  ["eq", "$success_action_status", "200"],
                  # The value of the form field must start with the specified prefix. For example, if the value of the key form field starts with user/user1, the condition is ["starts-with", "$key", "user/user1"]. 
                  ["starts-with", "$key", upload_dir],
                  # Specify the minimum and maximum sizes of the object that can be uploaded. Unit: bytes. 
                  ["content-length-range", 1, 1000000],
                  # Specify allowable file types.
                  ["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': host,
              'dir': upload_dir
              # Specify additional parameters.
          }
          return json.dumps(response)
      
      import com.aliyun.help.demo.uploading_to_oss_directly_postsignature.config.OssConfig;
      import com.aliyun.oss.ClientException;
      import com.aliyun.oss.OSS;
      import com.aliyun.oss.OSSException;
      import com.aliyun.oss.common.utils.BinaryUtil;
      import com.aliyun.oss.model.MatchMode;
      import com.aliyun.oss.model.PolicyConditions;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.ResponseBody;
      import org.codehaus.jettison.json.JSONObject;
      import java.util.Date;
      import com.aliyun.oss.OSSClientBuilder;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Bean;
      import javax.annotation.PreDestroy;
      
      @Controller
      public class PostSignatureController {
          @Autowired
          private OSS ossClient;
      
          @Autowired
          private OssConfig ossConfig;
      
          @GetMapping("/get_post_signature_for_oss_upload")
          @ResponseBody
          public String generatePostSignature() {
              JSONObject response = new JSONObject();
              try {
                  long expireEndTime = System.currentTimeMillis() + ossConfig.getExpireTime() * 1000;
                  Date expiration = new Date(expireEndTime);
                  PolicyConditions policyConds = new PolicyConditions();
                  policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
                  policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, ossConfig.getDir());
                  String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
                  byte[] binaryData = postPolicy.getBytes("utf-8");
                  String encodedPolicy = BinaryUtil.toBase64String(binaryData);
                  String postSignature = ossClient.calculatePostSignature(postPolicy);
                  response.put("ossAccessKeyId", ossConfig.getAccessKeyId());
                  response.put("policy", encodedPolicy);
                  response.put("signature", postSignature);
                  response.put("dir", ossConfig.getDir());
                  response.put("host", ossConfig.getHost());
              } 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.");
              // Assume that the method exists.
              System.out.println("HTTP Status Code: " + oe.getRawResponseError()); 
              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());
          } finally {
              if (ossClient != null) {
                  ossClient.shutdown();
              }
              return response.toString();
          }
        }
      }
      
      @Configuration
      public class OssConfig {
          /**
           * Replace <YOUR-ENDPOINT> with the endpoint of the region in which the bucket is located, such as oss-cn-hangzhou.aliyuncs.com.
           */
          private String endpoint = "<YOUR-ENDPOINT>";
          /**
           * Replace <YOUR-BUCKET> with the name of the bucket.
           */
          private String bucket = "<YOUR-BUCKET>";
          /**
           * Specify the prefix in the name of the object in OSS.
           */
          private String dir = "user-dir-prefix/";
          /**
           * Specify the validity period. Unit: seconds.
           */
          private long expireTime = 3600;
          /**
           * Create a host.
           */
          private String host = "http://" + bucket + "." + endpoint;
          /**
           * Obtain the AccessKey ID from the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
           */
          private String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
          /**
           * Obtain the AccessKey secret from the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
           */
          private String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
      
          private OSS ossClient;
          @Bean
          public OSS getOssClient() {
              ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
              return ossClient;
          }
          @Bean
          public String getHost() {
              return host;
          }
          @Bean
          public String getAccessKeyId() {
              return accessKeyId;
          }
          @Bean
          public long getExpireTime() {
              return expireTime;
          }
          @Bean
          public String getDir() {
              return dir;
          }
      
          @PreDestroy
          public void onDestroy() {
              ossClient.shutdown();
          }
      }
      
      
      package main
      
      import (
          "crypto/hmac"
          "crypto/sha1"
          "encoding/base64"
          "encoding/json"
          "fmt"
          "io"
          "net/http"
          "os"
          "time"
      )
      
      var (
          // Obtain the AccessKey ID from the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable. 
          accessKeyId = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
          // Obtain the AccessKey secret from the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable. 
          accessKeySecret = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
          // Specify the host. Format: BucketName.Endpoint. Replace ${your-bucket} with the name of the bucket. Replace ${your-endpoint} with the OSS endpoint, such as oss-cn-hangzhou.aliyuncs.com. 
          host = "http://${your-bucket}.${your-endpoint}"
          // Specify the prefix in the name of the object that you want to upload to OSS. 
          uploadDir = "user-dir-prefix/"
          // Specify the validity period. Unit: seconds. 
          expireTime = int64(3600)
      )
      
      type ConfigStruct struct {
          Expiration string     `json:"expiration"`
          Conditions [][]string `json:"conditions"`
      }
      type PolicyToken struct {
          AccessKeyId string `json:"ossAccessKeyId"`
          Host        string `json:"host"`
          Signature   string `json:"signature"`
          Policy      string `json:"policy"`
          Directory   string `json:"dir"`
      }
      
      func getGMTISO8601(expireEnd int64) string {
          return time.Unix(expireEnd, 0).UTC().Format("2006-01-02T15:04:05Z")
      }
      func getPolicyToken() string {
          now := time.Now().Unix()
          expireEnd := now + expireTime
          tokenExpire := getGMTISO8601(expireEnd)
          var config ConfigStruct
          config.Expiration = tokenExpire
          var condition []string
          condition = append(condition, "starts-with")
          condition = append(condition, "$key")
          condition = append(condition, uploadDir)
          config.Conditions = append(config.Conditions, condition)
          result, err := json.Marshal(config)
          if err != nil {
          fmt.Println("callback json err:", err)
          return ""
          }
          encodedResult := base64.StdEncoding.EncodeToString(result)
          h := hmac.New(sha1.New, []byte(accessKeySecret))
          io.WriteString(h, encodedResult)
          signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
          policyToken := PolicyToken{
          AccessKeyId: accessKeyId,
          Host:        host,
          Signature:   signedStr,
          Policy:      encodedResult,
          Directory:   uploadDir,
          }
          response, err := json.Marshal(policyToken)
          if err != nil {
          fmt.Println("json err:", err)
          return ""
          }
          return string(response)
      }
      func handler(w http.ResponseWriter, r *http.Request) {
          if r.URL.Path == "/" {
          http.ServeFile(w, r, "templates/index.html")
          return
          } else if r.URL.Path == "/get_post_signature_for_oss_upload" {
          policyToken := getPolicyToken()
          w.Header().Set("Content-Type", "application/json")
          w.Write([]byte(policyToken))
          return
          }
          http.NotFound(w, r)
      }
      func main() {
          http.HandleFunc("/", handler)
          http.ListenAndServe(":8080", nil)
      }
      
      <?php
      function gmt_iso8601($time)
      {
          return str_replace('+00:00', '.000Z', gmdate('c', $time));
      }
      
      // Obtain access credentials from environment variables. Before you run the sample code, make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables are configured. 
      $accessKeyId = getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
      $accessKeySecret = getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
      // Specify a host. Format: <YOUR-BUCKET>.<YOUR-ENDPOINT>. 
      $host = 'http://<YOUR-BUCKET>.<YOUR-ENDPOINT>';
      // Specify the prefix in the name of the object you want to upload. 
      $dir = 'user-dir-prefix/';          
      
      $now = time();
      // Specify the expiration time of the policy. If the expiration time elapses, the access is denied. In this example, the expiration time is set to 10 seconds. 
      $expire = 30;  
      $end = $now + $expire;
      $expiration = gmt_iso8601($end);
      
      // Specify the maximum size of the object that can be uploaded. 
      $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
      $conditions[] = $condition;
      
      // Specify the object that can be uploaded. In this example, only an object whose name starts with the value of the $dir parameter can be uploaded. This is an optional setting that prevents the object from being uploaded to a different directory in the bucket by using the policy. 
      $start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
      $conditions[] = $start;
      
      
      $arr = array('expiration' => $expiration, 'conditions' => $conditions);
      $policy = json_encode($arr);
      $base64_policy = base64_encode($policy);
      $string_to_sign = $base64_policy;
      $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $accessKeySecret, true));
      
      $response = array();
      $response['ossAccessKeyId'] = $accessKeyId;
      $response['host'] = $host;
      $response['policy'] = $base64_policy;
      $response['signature'] = $signature;
      $response['dir'] = $dir;  
      echo json_encode($response);
      
      const express = require("express");
      const { Buffer } = require("buffer");
      const OSS = require("ali-oss");
      const app = express();
      const path = require("path");
      const config = {
        // Obtain the AccessKey ID from the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable. 
        accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
        // Obtain the AccessKey secret from the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable. 
        accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
        // Replace <YOUR-BUCKET> with the name of the bucket. 
        bucket: "<YOUR-BUCKET>",
        // Specify the prefix in the name of the object that you want to upload to OSS. 
        dir: "prefix/",
      };
      
      app.use(express.static(path.join(__dirname, "templates")));
      
      app.get("/get_post_signature_for_oss_upload", async (req, res) => {
        const client = new OSS(config);
        const date = new Date();
        // Specify the validity period of the signature. Unit: seconds. 
        date.setSeconds(date.getSeconds() + 3600);
        const policy = {
          expiration: date.toISOString(),
          conditions: [
            // Specify the size limit on the object that can be uploaded. 
            ["content-length-range", 0, 1048576000],
            // Specify the bucket to which the object can be uploaded. 
            { bucket: client.options.bucket },
          ],
        };
        const formData = await client.calculatePostSignature(policy);
        const host = `http://${config.bucket}.${
          (await client.getBucketLocation()).location
        }.aliyuncs.com`.toString();
        const params = {
          policy: formData.policy,
          signature: formData.Signature,
          ossAccessKeyId: formData.OSSAccessKeyId,
          host,
          dir: config.dir,
        };
        res.json(params);
      });
      
      app.get(/^(.+)*\.(html|js)$/i, async (req, res) => {
        res.sendFile(path.join(__dirname, "./templates", req.originalUrl));
      });
      
      app.listen(8000, () => {
        console.log("http://127.0.0.1:8000");
      });
      
      require 'sinatra'
      require 'base64'
      require 'open-uri'
      require 'cgi'
      require 'openssl'
      require 'json'
      require 'sinatra/reloader'
      require 'sinatra/content_for'
      
      # Set the path of the public-folder folder to the templates subfolder within the current folder.
      set :public_folder, File.dirname(__FILE__) + '/templates'
      
      # Obtain the AccessKey ID from the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable. 
      $access_key_id = ENV['ALIBABA_CLOUD_ACCESS_ID']
      # Obtain the AccessKey secret from the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable. 
      $access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_SECRET']
      
      # Specify the host. The host is in the <bucketname>.<endpoint> format. 
      $host = 'http://<bucketname>.<endpoint>';
      
      # Specify the prefix in the name of the object you want to upload. 
      $upload_dir = 'user-dir-prefix/'
      # Specify the validity period. Unit: seconds. 
      $expire_time = 30
      $server_ip = "0.0.0.0"
      $server_port = 8000
      
      if ARGV.length == 1 
        $server_port = ARGV[0]
      elsif ARGV.length == 2
        $server_ip = ARGV[0]
        $server_port = ARGV[1]
      end
      
      puts "App server is running on: http://#{$server_ip}:#{$server_port}"
      
      def hash_to_jason(source_hash)
        jason_string = source_hash.to_json;    
      
        jason_string.gsub!("\":[", "\": [")
        jason_string.gsub!("\",\"", "\", \"")
        jason_string.gsub!("],\"", "], \"")
        jason_string.gsub!("\":\"", "\": \"")
      
        jason_string
      end
      
      
      def get_token()
        expire_syncpoint = Time.now.to_i + $expire_time
        expire = Time.at(expire_syncpoint).utc.iso8601()
        response.headers['expire'] = expire
        policy_dict = {}
        condition_arrary = Array.new
        array_item = Array.new
        array_item.push('starts-with')
        array_item.push('$key')
        array_item.push($upload_dir)
        condition_arrary.push(array_item)
        policy_dict["conditions"] = condition_arrary
        policy_dict["expiration"] = expire
        policy = hash_to_jason(policy_dict)
        policy_encode = Base64.strict_encode64(policy).chomp;
        h = OpenSSL::HMAC.digest('sha1', $access_key_secret, policy_encode)
        hs = Digest::MD5.hexdigest(h)
        sign_result = Base64.strict_encode64(h).strip()
        token_dict = {}
        token_dict['ossAccessKeyId'] = $access_key_id
        token_dict['host'] = $host
        token_dict['policy'] = policy_encode
        token_dict['signature'] = sign_result 
        token_dict['expire'] = expire_syncpoint
        token_dict['dir'] = $upload_dir
        result = hash_to_jason(token_dict)
        result
      end
      
      set :bind, $server_ip
      set :port, $server_port
      
      get '/get_post_signature_for_oss_upload' do
        token = get_token()
        puts "Token: #{token}"
        token
      end
      
      get '/*' do
        puts "********************* GET "
        send_file File.join(settings.public_folder, 'index.html')
      end
      
      end
      
      if ARGV.length == 1 
        $server_port = ARGV[0]
      elsif ARGV.length == 2
        $server_ip = ARGV[0]
        $server_port = ARGV[1]
      end
      
      $server_ip = "0.0.0.0"
      $server_port = 8000
      
      puts "App server is running on: http://#{$server_ip}:#{$server_port}"
      
      set :bind, $server_ip
      set :port, $server_port
      
      get '/get_sts_token_for_oss_upload' do
        token = get_sts_token_for_oss_upload()
        response = {
          "AccessKeyId" => token["Credentials"]["AccessKeyId"],
          "AccessKeySecret" => token["Credentials"]["AccessKeySecret"],
          "SecurityToken" => token["Credentials"]["SecurityToken"]
        }
        response.to_json
      end
      
      get '/*' do
        puts "********************* GET "
        send_file File.join(settings.public_folder, 'index.html')
      end
      
      using Microsoft.AspNetCore.Builder;
      using Microsoft.Extensions.DependencyInjection;
      using Microsoft.AspNetCore.Http;
      using System.IO;
      using System.Collections.Generic;
      using System;
      using System.Globalization;
      using System.Text;
      using System.Security.Cryptography;
      using Newtonsoft.Json;
      using Microsoft.AspNetCore.Http.Extensions;
      using Microsoft.AspNetCore.Mvc;
      using Microsoft.Extensions.Logging;
      
      namespace YourNamespace
      {
          public class Program
          {
              private ILogger<Program> _logger;
              // Obtain the AccessKey ID from the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable. 
              public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
              // Obtain the AccessKey secret from the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable. 
              public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
              // Specify the host. Format: BucketName.Endpoint. Replace <YOUR-BUCKET> with the name of the bucket. Replace <YOUR-ENDPOINT> with the endpoint of the region in which the bucket is located, such as oss-cn-hangzhou.aliyuncs.com. 
              public string Host { get; set; } = "<YOUR-BUCKET>.<YOUR-ENDPOINT>";
              // Specify the prefix in the name of the object that you want to upload to OSS. 
              public string UploadDir { get; set; } = "user-dir-prefix/";
              // Specify the validity period. Unit: seconds. 
              public int ExpireTime { get; set; } = 3600;
              public class PolicyConfig
              {
                  public string expiration { get; set; }
                  public List<List<object>> conditions { get; set; }
              }
              public class PolicyToken
              {
                  public string Accessid { get; set; }
                  public string Policy { get; set; }
                  public string Signature { get; set; }
                  public string Dir { get; set; }
                  public string Host { get; set; }
                  public string Expire { get; set; }
              }
              public static void Main(string[] args)
              {
                  var builder = WebApplication.CreateBuilder(args);
                  var app = builder.Build();
      
                  builder.Logging.AddConsole();
                  var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
      
                  app.UseStaticFiles(); 
      
                  app.MapGet("/", async (context) =>
                  {
                      var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
                      var htmlContent = await File.ReadAllTextAsync(filePath);
                      await context.Response.WriteAsync(htmlContent);
                      logger.LogInformation("GET request to root path");
                  });
      
                  app.MapGet("/get_post_signature_for_oss_upload", async (context) =>
                  {
                      var program = new Program(logger);
                      var token = program.GetPolicyToken();
      
                      logger.LogInformation($"Token: {token}");
      
                      context.Response.ContentType = "application/json";
                      await context.Response.WriteAsync(token);
                  });
      
                  app.Run();
              }
      
              public Program(ILogger<Program> logger)
              {
                  _logger = logger;
              }
      
              private string ToUnixTime(DateTime dateTime)
              {
                  return ((DateTimeOffset)dateTime).ToUnixTimeSeconds().ToString();
              }
      
              private string GetPolicyToken()
              {
                  var expireDateTime = DateTime.Now.AddSeconds(ExpireTime);
                  var config = new PolicyConfig
                  {
                      expiration = FormatIso8601Date(expireDateTime),
                      conditions = new List<List<object>>()
                  };
                  config.conditions.Add(new List<object>
                  {
                      "content-length-range", 0, 1048576000
                  });
                  var policy = JsonConvert.SerializeObject(config);
                  var policyBase64 = EncodeBase64("utf-8", policy);
                  var signature = ComputeSignature(AccessKeySecret, policyBase64);
                  var policyToken = new PolicyToken
                  {
                      Accessid = AccessKeyId,
                      Host = Host,
                      Policy = policyBase64,
                      Signature = signature,
                      Expire = ToUnixTime(expireDateTime),
                      Dir = UploadDir
                  };
                  return JsonConvert.SerializeObject(policyToken);
              }
      
              private string FormatIso8601Date(DateTime dtime)
              {
                  return dtime.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'",
                                          CultureInfo.CurrentCulture);
              }
      
              private string EncodeBase64(string codeType, string code)
              {
                  string encode = "";
                  byte[] bytes = Encoding.GetEncoding(codeType).GetBytes(code);
                  try
                  {
                      encode = Convert.ToBase64String(bytes);
                  }
                  catch
                  {
                      encode = code;
                  }
                  return encode;
              }
      
              private string ComputeSignature(string key, string data)
              {
                  using (var algorithm = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
                  {
                      return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(data)));
                  }
              }
          }
      }
      
  2. クライアントは、署名やPOSTポリシーなどの情報を使用してPostObject操作を呼び出し、HTMLフォームを使用してオブジェクトをOSSにアップロードします。

    次の例ではJavaScriptが使用されます。

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Upload an object to OSS</title>
    </head>
    <body>
      <div class="container">
        <form>
          <div class="mb-3">
            <label for="file" class="form-label">Select the object</label>
            <input type="file" class="form-control" id="file" name="file" required>
          </div>
          <button type="submit" class="btn btn-primary">Upload</button>
        </form>
      </div>
      <script type="text/javascript">
          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())
              .then(data => {
                const formData = new 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);
                // Set file to the last form field. No particular order is required for other form fields. 
                formData.append('file', file);
                fetch(data.host, { method: 'POST', body: formData},).then((res) => {
                  console.log(res);
                  alert ('Object Uploaded');
                });
              })
              .catch(error => {
                console.log('Error occurred while getting OSS upload parameters:', error);
              });
          });
      </script>
    </body>
    </html>
    

使用上の注意

データセキュリティ

オブジェクトの上書き

デフォルトでは、既存のオブジェクトは同じ名前のアップロードされたオブジェクトで上書きされます。 次の方法を使用して、既存のオブジェクトが予期せず上書きされないようにします。

  • バケットのバージョン管理の有効化

    バケットのバージョン管理を有効にすると、バケット内で上書きされたオブジェクトは以前のバージョンとして保存されます。 以前のバージョンのオブジェクトはいつでも復元できます。 詳細については、「概要」をご参照ください。

  • アップロードリクエストにx-oss-forbid-overwriteパラメーターを含める

    アップロードリクエストのヘッダーにx-oss-forbid-overwriteパラメーターを追加し、このパラメーターをtrueに設定できます。 既存のオブジェクトと同じ名前のオブジェクトをアップロードすると、オブジェクトのアップロードに失敗し、FileAlreadyExistsエラーコードが返されます。 このパラメーターをリクエストヘッダーに追加しない場合、またはこのパラメーターをfalseに設定した場合、オブジェクトはバケット内の同じ名前を持つ既存のオブジェクトを上書きします。

承認済みアップロード

  • OSSは、バケットおよびオブジェクトレベルでのアクセス制御を提供し、第三者による不正なデータのバケットへのアップロードを防止します。 詳細については、「概要」をご参照ください。

  • 署名付きURLを使用して、サードパーティのユーザーに特定のオブジェクトをアップロードする権限を付与できます。 このようにして、サードパーティのユーザーは、アクセス資格情報や承認なしでデータをアップロードできます。 OSSは、アップロードされたデータをオブジェクトとしてバケットに保存します。 詳細については、「署名付きURLでローカルファイルをアップロード」をご参照ください。

PUTリクエストコスト

多数のオブジェクトをアップロードし、オブジェクトのストレージクラスをDeep Cold Archiveに設定する場合は、高いPUTリクエスト料金が請求されます。 オブジェクトのアップロード時にオブジェクトのストレージクラスを標準に設定し、標準オブジェクトのストレージクラスをDeep Cold Archiveに変換するようにライフサイクルルールを設定することを推奨します。 これにより、PUTリクエスト料金が削減されます。

OSS-HDFSが有効なバケットへのオブジェクトのアップロード

OSS-HDFSの安定性を維持し、データの損失を防ぐために、オブジェクトを. dlsdata /OSS-HDFSでサポートされていないメソッドを使用してOSS-HDFSが有効になっているバケットのディレクトリ。

アップロード性能チューニング

多数のオブジェクトをアップロードし、オブジェクトの名前にタイムスタンプや文字などの連続したプレフィックスが含まれている場合、複数のオブジェクトインデックスが1つのパーティションに格納される可能性があります。 その結果、これらのオブジェクトを照会するために多数の要求が送信されると、待ち時間が増大する。 多数のオブジェクトをアップロードする場合は、シーケンシャルプレフィックスではなくランダムプレフィックスを使用してオブジェクト名を指定することをお勧めします。 詳細については、「OSSパフォーマンスとスケーラビリティのベストプラクティス」をご参照ください。