All Products
Search
Document Center

Object Storage Service:Form upload

Last Updated:Sep 24, 2026

Form upload memungkinkan aplikasi web mengunggah objek langsung ke OSS melalui form HTML standar. Browser mengirim permintaan PostObject ke OSS tanpa melewati server aplikasi Anda, sehingga mengurangi beban server serta meningkatkan efisiensi dan stabilitas unggah.

Batasan

Objek yang diunggah menggunakan form upload tidak boleh melebihi 5 GB.

Skenario

Kasus penggunaan umum untuk form upload:

  • Unggah data pengguna: Unggah avatar, foto KTP, atau materi verifikasi identitas selama pendaftaran akun atau pembaruan profil.

  • Berbagi dan penyimpanan file: Unggah dokumen, gambar, audio, dan video ke Alibaba Cloud melalui drive online atau platform kolaborasi.

  • Penerbitan konten: Unggah gambar dan lampiran di blog, forum, serta platform tanya jawab.

  • E-dagang: Unggah gambar produk, deskripsi, dan dokumen kualifikasi. Konsumen mengunggah faktur atau materi pendukung selama pembelian.

  • Pendidikan daring: Siswa mengirimkan tugas dan proyek. Guru mengunggah materi ajar dan bahan pelajaran.

  • Rekrutmen: Pelamar kerja mengunggah CV dan portofolio. Perusahaan mengunggah logo dan iklan lowongan kerja.

  • Survei dan umpan balik: Unggah dokumen pendukung atau bukti bersama kuesioner daring.

  • Kolaborasi pengembangan: Unggah file kode atau dokumen proyek dari platform seperti GitHub dan GitLab.

  • Menghindari timeout dan batas ukuran pada platform relay pihak ketiga: Saat Anda mengunggah objek melalui platform relay pihak ketiga, seperti CDN Cloudflare atau fungsi arsitektur tanpa server (serverless), Anda mungkin mengalami error timeout 524 atau batas ukuran objek (misalnya, 30 MB). Anda dapat menggunakan form upload OSS untuk mengunggah objek langsung dari klien, melewati lapisan relay guna menghindari timeout dan batas ukuran tersebut. Server aplikasi menghasilkan signature dan kebijakan POST, sedangkan klien menggunakan form HTML untuk mengirim (POST) objek langsung ke titik akhir OSS. Metode ini mendukung objek hingga ukuran 5 GB.

Cara kerja

Klien memperoleh signature dan kebijakan POST dari server aplikasi, lalu mengunggah objek secara langsung tanpa menggunakan SDK OSS. Kebijakan POST dapat membatasi atribut objek seperti ukuran dan jenis. Form upload tidak mendukung unggah multi-bagian (multipart upload) atau unggah yang dapat dilanjutkan (resumable upload). Untuk informasi lebih lanjut, lihat PostObject.

Alur unggah menggunakan signature Post dan Kebijakan Post:

  1. Klien meminta signature Post, kebijakan Post, dan informasi lainnya dari server aplikasi.

  2. Server aplikasi menghasilkan signature Post, kebijakan Post, dan informasi terkait, lalu mengembalikannya ke klien.

  3. Klien memanggil PostObject dengan signature Post dan kebijakan Post untuk mengunggah file ke OSS melalui form HTML.

  4. OSS mengembalikan respons sukses ke klien.

Prosedur

  1. Server menghasilkan signature dan kebijakan POST.

    • Proyek contoh: postsignature.zip

    • Contoh

      Hasilkan signature Post dan kebijakan Post di sisi server:

      Catatan

      Mendukung penerapan satu klik ke Function Compute (FC).oss-upload-post-signature-app

      Python

      import os
      from hashlib import sha1 as sha
      import json
      import base64
      import hmac
      import datetime
      import time
      
      # Konfigurasikan variabel lingkungan OSS_ACCESS_KEY_ID.
      access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
      # Konfigurasikan variabel lingkungan OSS_ACCESS_KEY_SECRET.
      access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
      # Ganti <YOUR_BUCKET> dengan nama bucket Anda.
      bucket = '<YOUR_BUCKET>'
      # Format host adalah bucketname.endpoint. Ganti <YOUR_BUCKET> dengan nama bucket Anda. Ganti <YOUR_ENDPOINT> dengan titik akhir OSS, misalnya oss-cn-hangzhou.aliyuncs.com.
      host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
      # Tentukan awalan untuk file yang akan diunggah ke OSS.
      upload_dir = 'user-dir-prefix/'
      # Tentukan waktu kedaluwarsa dalam detik.
      expire_time = 3600
      
      
      def generate_expiration(seconds):
          """
          Hasilkan waktu kedaluwarsa dengan menentukan periode validitas dalam detik.
          :param seconds: Periode validitas dalam detik.
          :return: String waktu ISO 8601, seperti "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):
          """
          Hasilkan string signature.
          :param access_key_secret: Rahasia AccessKey dari akun yang memiliki izin untuk mengakses bucket tujuan.
          :param expiration: Waktu kedaluwarsa signature, dalam format ISO 8601 dan UTC. Contoh: "2014-12-01T12:00:00.000Z".
          :param conditions: Kondisi kebijakan yang digunakan untuk membatasi nilai yang diizinkan saat mengunggah form.
          :param policy_extra_props: Parameter kebijakan tambahan. Jika parameter baru ditambahkan ke kebijakan, Anda dapat meneruskannya sebagai dictionary.
          :return: signature, string signature.
          """
          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 = {
              # Periode validitas.
              "expiration": generate_expiration(expire_time),
              # Batasan.
              "conditions": [
                  # Kode status yang dikembalikan setelah unggah berhasil jika success_action_redirect tidak ditentukan. Nilai default adalah 204.
                  ["eq", "$success_action_status", "200"],
                  # Nilai bidang form harus dimulai dengan awalan yang ditentukan. Misalnya, untuk menentukan bahwa nilai key harus dimulai dengan user/user1, Anda dapat menulis ["starts-with", "$key", "user/user1"].
                  ["starts-with", "$key", upload_dir],
                  # Batasi ukuran minimum dan maksimum objek yang diunggah dalam byte.
                  ["content-length-range", 1, 1000000],
                  # Batasi file yang diunggah hanya ke jenis gambar tertentu.
                  ["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
              # Anda dapat menambahkan parameter lain di sini.
          }
          return json.dumps(response)
      

      Java

      package com.aliyun.sample;
      
      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;
      
      @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.");
                  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());
              } catch (Exception e) {
                  System.out.println("Caught an unexpected exception: " + e.getMessage());
              }
              return response.toString();
          }
      }

      Go

      package main
      
      import (
      	"crypto/hmac"
      	"crypto/sha1"
      	"encoding/base64"
      	"encoding/json"
      	"fmt"
      	"io"
      	"net/http"
      	"os"
      	"time"
      )
      
      var (
      	// Konfigurasikan variabel lingkungan OSS_ACCESS_KEY_ID.
      	accessKeyId = os.Getenv("OSS_ACCESS_KEY_ID")
      	// Konfigurasikan variabel lingkungan OSS_ACCESS_KEY_SECRET.
      	accessKeySecret = os.Getenv("OSS_ACCESS_KEY_SECRET")
      	// Format host adalah bucketname.endpoint. Ganti ${your-bucket} dengan nama bucket Anda. Ganti ${your-endpoint} dengan titik akhir OSS, misalnya oss-cn-hangzhou.aliyuncs.com.
      	host = "http://${your-bucket}.${your-endpoint}"
      	// Tentukan awalan untuk file yang akan diunggah ke OSS.
      	uploadDir = "user-dir-prefix/"
      	// Tentukan waktu kedaluwarsa dalam detik.
      	expireTime = int64(3600)
      )
      
      type ConfigStruct struct {
      	Expiration string          `json:"expiration"`
      	Conditions [][]interface{} `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
      
      	// Tambahkan batasan awalan file.
      	config.Conditions = append(config.Conditions, []interface{}{"starts-with", "$key", uploadDir})
      
      	// Tambahkan batasan ukuran file, misalnya dari 1 KB hingga 10 MB.
      	minSize := int64(1024)
      	maxSize := int64(10 * 1024 * 1024)
      	config.Conditions = append(config.Conditions, []interface{}{"content-length-range", minSize, maxSize})
      
      	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

      <?php
      function gmt_iso8601($time)
      {
          return str_replace('+00:00', '.000Z', gmdate('c', $time));
      }
      
      // Peroleh kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh ini, pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID dan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah dikonfigurasi.
      $accessKeyId = getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
      $accessKeySecret = getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
      // Format $host adalah '<YOUR-BUCKET>.<YOUR-ENDPOINT>'. Ganti variabel tersebut dengan informasi aktual Anda.
      $host = 'http://<YOUR-BUCKET>.<YOUR-ENDPOINT>';
      // Awalan yang ditentukan pengguna saat mengunggah file.
      $dir = 'user-dir-prefix/';          
      
      $now = time();
      // Tetapkan kebijakan kedaluwarsa dalam 10 detik. Setelah periode ini, kebijakan menjadi tidak valid.
      $expire = 30;  
      $end = $now + $expire;
      $expiration = gmt_iso8601($end);
      
      // Ukuran file maksimum. Anda dapat mengaturnya sendiri.
      $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
      $conditions[] = $condition;
      
      // Data yang diunggah harus dimulai dengan $dir, jika tidak, unggah akan gagal. Langkah ini tidak wajib tetapi direkomendasikan demi keamanan untuk mencegah pengguna mengunggah ke direktori lain melalui kebijakan.
      $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);
      

      Node.js

      const express = require("express");
      const { Buffer } = require("buffer");
      const OSS = require("ali-oss");
      const app = express();
      const path = require("path");
      const config = {
        // Konfigurasikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
        accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
        // Konfigurasikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
        accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
        // Ganti <YOUR-BUCKET> dengan nama bucket Anda.
        bucket: "<YOUR-BUCKET>",
        // Tentukan awalan untuk file yang akan diunggah ke 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();
        // Tetapkan periode validitas signature dalam detik.
        date.setSeconds(date.getSeconds() + 3600);
        const policy = {
          expiration: date.toISOString(),
          conditions: [
            // Tetapkan batas ukuran untuk file yang diunggah.
            ["content-length-range", 0, 1048576000],
            // Batasi bucket tempat file dapat diunggah.
            { 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");
      });
      

      Ruby

      require 'sinatra'
      require 'base64'
      require 'open-uri'
      require 'cgi'
      require 'openssl'
      require 'json'
      require 'sinatra/reloader'
      require 'sinatra/content_for'
      
      # Atur jalur folder publik ke folder templat di direktori saat ini.
      set :public_folder, File.dirname(__FILE__) + '/templates'
      
      # Konfigurasikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
      $access_key_id = ENV['ALIBABA_CLOUD_ACCESS_ID']
      # Konfigurasikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
      $access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_SECRET']
      
      # Format $host adalah <bucketname>.<endpoint>. Ganti <bucketname> dan <endpoint> dengan informasi Anda yang sebenarnya.
      $host = 'http://<bucketname>.<endpoint>';
      
      # Awalan untuk file yang diunggah pengguna.
      $upload_dir = 'user-dir-prefix/'
      # Waktu kedaluwarsa dalam detik.
      $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
      

      C#

      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;
              // Konfigurasikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
              public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
              // Konfigurasikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
              public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
              // Format host adalah bucketname.endpoint. Ganti <YOUR-BUCKET> dengan nama bucket Anda. Ganti <YOUR-ENDPOINT> dengan titik akhir OSS, misalnya oss-cn-hangzhou.aliyuncs.com.
              public string Host { get; set; } = "<YOUR-BUCKET>.<YOUR-ENDPOINT>";
              // Tentukan awalan untuk file yang akan diunggah ke OSS.
              public string UploadDir { get; set; } = "user-dir-prefix/";
              // Tentukan waktu kedaluwarsa dalam detik.
              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. Klien memanggil operasi PostObject dengan signature dan kebijakan POST untuk mengunggah objek ke OSS menggunakan form HTML.

    Contoh 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);
                // Setel file sebagai bidang form terakhir. Tidak ada urutan khusus yang diperlukan untuk bidang form lainnya. 
                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>
    

Catatan penggunaan

Keamanan data

Penimpaan objek

Secara default, OSS menimpa objek yang sudah ada dengan nama yang sama. Anda dapat mencegah penimpaan tak terduga dengan metode berikut:

  • Aktifkan Pengendalian versi untuk bucket

    Jika Pengendalian versi diaktifkan, objek yang ditimpa disimpan sebagai versi sebelumnya yang dapat Anda pulihkan kapan saja. Untuk informasi lebih lanjut, lihat Pengendalian versi.

  • Sertakan parameter x-oss-forbid-overwrite dalam permintaan unggah

    Tambahkan parameter x-oss-forbid-overwrite ke bidang form dan atur nilainya ke true. Jika objek dengan nama yang sama sudah ada, unggah akan gagal dengan error FileAlreadyExists. Jika parameter ini tidak disertakan atau diatur ke false, objek yang diunggah akan menimpa objek yang sudah ada.

Unggah berotorisasi

  • OSS menyediakan kontrol akses tingkat bucket dan tingkat objek untuk mencegah unggah tidak sah. Untuk informasi lebih lanjut, lihat Ikhtisar izin dan kontrol akses.

  • Anda dapat menggunakan URL yang ditandatangani (signed URL) untuk memungkinkan pengguna pihak ketiga mengunggah objek tertentu tanpa kredensial akses. OSS menyimpan data yang diunggah sebagai objek dalam bucket. Untuk informasi lebih lanjut, lihat Unggah objek menggunakan URL yang telah ditandatangani sebelumnya.

Biaya permintaan PUT

Jika Anda ingin mengunggah sejumlah besar objek, secara langsung menentukan kelas penyimpanan Deep Cold Archive untuk objek yang akan diunggah mengakibatkan biaya biaya permintaan PUT yang tinggi. Kami menyarankan agar Anda terlebih dahulu menentukan kelas penyimpanan Standard untuk objek saat mengunggahnya, lalu menggunakan aturan siklus hidup untuk mengonversinya ke kelas penyimpanan Deep Cold Archive guna mengurangi biaya permintaan PUT.

Bucket dengan OSS-HDFS diaktifkan

Untuk menjaga stabilitas OSS-HDFS dan mencegah kehilangan data, jangan mengunggah objek ke direktori .dlsdata/ bucket yang telah diaktifkan OSS-HDFS menggunakan metode yang tidak didukung oleh OSS-HDFS.

Pengoptimalan kinerja unggah

Jika nama objek mengandung awalan berurutan seperti stempel waktu dan huruf, beberapa indeks mungkin disimpan dalam satu partisi, yang meningkatkan latensi kueri. Gunakan awalan acak alih-alih awalan berurutan saat mengunggah volume objek yang besar. Untuk informasi lebih lanjut, lihat Praktik terbaik kinerja OSS.