All Products
Search
Document Center

Object Storage Service:Form upload

Last Updated:Jan 22, 2026

Form upload allows you to directly upload objects to Object Storage Service (OSS) by using standard HTML forms from web applications. After an object is selected on the front-end page, the browser initiates a PostObject request to upload the object directly to OSS without routing through your application server. This reduces server workload and improves upload efficiency and stability.

Limitation

The size of the object that you want to upload by using form upload cannot exceed 5 GB.

Use cases

Form upload is widely used in web applications for scenarios that require direct browser-to-OSS file transfers, including:

  • User data upload: Profile pictures, identity verification documents, and personal information updates.

  • Object sharing and storage: Documents, images, audio, and video files on cloud storage and collaboration platforms.

  • Content creation and publishing: Articles with images and attachments on blogs, forums, and Q&A platforms.

  • E-commerce management: Product images, descriptions, and supporting materials from merchants and consumers.

  • Online education: Homework submissions and teaching materials upload.

  • Recruitment: Resume and portfolio uploads from job seekers.

  • Feedback and surveys: Supporting documents for online questionnaires.

  • Software development: Project files and code uploads on collaboration platforms.

Solution

The client requests the signature and POST policy required by a PostObject request from the application server. The client then uses the signature and POST policy to upload objects directly without requiring OSS SDKs. You can use the POST policy generated by the application server to limit object attributes, such as object size and type. This solution is suitable for scenarios in which you want to upload objects by using HTML forms. This solution does not support multipart upload and resumable upload. For more information, see PostObject.

The following process describes how a server authorizes a client to upload a file to OSS using a Post signature and Post Policy.

image
  1. The client requests the Post signature, Post Policy, and other information from the application server.

  2. The application server generates and returns the Post signature, Post Policy, and other information to the client.

  3. The client uses the Post signature, Post Policy, and other information to call the PostObject operation and upload the file to OSS through an HTML form.

  4. OSS returns a success response to the client.

Procedure

  1. The server generates information, such as the signature and POST policy.

    • Sample project: postsignature.zip

    • Examples

      The following sample code shows how to generate the Post signature, Post Policy, and other information on the server:

      Note

      This code supports one-click deployment. You can deploy this code to Function Compute (FC) with a single click.oss-upload-post-signature-app

      Python

      import os
      from hashlib import sha1 as sha
      import json
      import base64
      import hmac
      import datetime
      import time
      
      # Configure the OSS_ACCESS_KEY_ID environment variable.
      access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
      # Configure the OSS_ACCESS_KEY_SECRET environment variable.
      access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
      # Replace <YOUR_BUCKET> with your bucket name.
      bucket = '<YOUR_BUCKET>'
      # The host format is bucketname.endpoint. Replace <YOUR_BUCKET> with your bucket name. Replace <YOUR_ENDPOINT> with the OSS endpoint, such as oss-cn-hangzhou.aliyuncs.com.
      host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
      # Specify the prefix for files to upload to OSS.
      upload_dir = 'user-dir-prefix/'
      # Specify the expiration time in seconds.
      expire_time = 3600
      
      
      def generate_expiration(seconds):
          """
          Generate an expiration time by specifying a validity period in seconds.
          :param seconds: The validity period in seconds.
          :return: An ISO 8601 time string, such as "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 of an account that has permissions to access the destination bucket.
          :param expiration: The signature expiration time, in ISO 8601 format and UTC. Example: "2014-12-01T12:00:00.000Z".
          :param conditions: Policy conditions used to limit the allowed values when uploading a form.
          :param policy_extra_props: Additional policy parameters. If new parameters are added to the policy, you can pass them as a dictionary.
          :return: signature, 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 = {
              # Validity period.
              "expiration": generate_expiration(expire_time),
              # Constraints.
              "conditions": [
                  # The status code to return after a successful upload if success_action_redirect is not specified. The default value is 204.
                  ["eq", "$success_action_status", "200"],
                  # The value of the form field must start with the specified prefix. For example, to specify that the value of key must start with user/user1, you can write ["starts-with", "$key", "user/user1"].
                  ["starts-with", "$key", upload_dir],
                  # Limit the minimum and maximum allowed size of the uploaded object in bytes.
                  ["content-length-range", 1, 1000000],
                  # Limit the uploaded file to specified image 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
              # You can add other parameters here.
          }
          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 (
      	// Configure the OSS_ACCESS_KEY_ID environment variable.
      	accessKeyId = os.Getenv("OSS_ACCESS_KEY_ID")
      	// Configure the OSS_ACCESS_KEY_SECRET environment variable.
      	accessKeySecret = os.Getenv("OSS_ACCESS_KEY_SECRET")
      	// The host format is bucketname.endpoint. Replace ${your-bucket} with your bucket name. Replace ${your-endpoint} with the OSS endpoint, such as oss-cn-hangzhou.aliyuncs.com.
      	host = "http://${your-bucket}.${your-endpoint}"
      	// Specify the prefix for files to upload to OSS.
      	uploadDir = "user-dir-prefix/"
      	// Specify the expiration time in seconds.
      	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
      
      	// Add a file prefix restriction.
      	config.Conditions = append(config.Conditions, []interface{}{"starts-with", "$key", uploadDir})
      
      	// Add a file size restriction, for example, from 1 KB to 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));
      }
      
      // Obtain access credentials from environment variables. Before you run this 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");
      // The format of $host is '<YOUR-BUCKET>.<YOUR-ENDPOINT>'. Replace the variables with your actual information.
      $host = 'http://<YOUR-BUCKET>.<YOUR-ENDPOINT>';
      // The prefix specified by the user when uploading a file.
      $dir = 'user-dir-prefix/';          
      
      $now = time();
      // Set the policy to expire in 10 seconds. After this period, the policy becomes invalid.
      $expire = 30;  
      $end = $now + $expire;
      $expiration = gmt_iso8601($end);
      
      // Maximum file size. You can set this yourself.
      $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
      $conditions[] = $condition;
      
      // The uploaded data must start with $dir, otherwise the upload will fail. This step is not required but is recommended for security to prevent users from uploading to other directories through 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);
      

      Node.js

      const express = require("express");
      const { Buffer } = require("buffer");
      const OSS = require("ali-oss");
      const app = express();
      const path = require("path");
      const config = {
        // Configure the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
        accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
        // Configure the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
        accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
        // Replace <YOUR-BUCKET> with your bucket name.
        bucket: "<YOUR-BUCKET>",
        // Specify the prefix for files 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();
        // Set the validity period of the signature in seconds.
        date.setSeconds(date.getSeconds() + 3600);
        const policy = {
          expiration: date.toISOString(),
          conditions: [
            // Set the size limit for the uploaded file.
            ["content-length-range", 0, 1048576000],
            // Restrict the bucket to which files 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");
      });
      

      Ruby

      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 to the templates folder in the current directory.
      set :public_folder, File.dirname(__FILE__) + '/templates'
      
      # Configure the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
      $access_key_id = ENV['ALIBABA_CLOUD_ACCESS_ID']
      # Configure the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
      $access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_SECRET']
      
      # The format of $host is <bucketname>.<endpoint>. Replace <bucketname> and <endpoint> with your actual information.
      $host = 'http://<bucketname>.<endpoint>';
      
      # The prefix for user-uploaded files.
      $upload_dir = 'user-dir-prefix/'
      # The expiration time in 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
      

      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;
              // Configure the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
              public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
              // Configure the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
              public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
              // The host format is bucketname.endpoint. Replace <YOUR-BUCKET> with your bucket name. Replace <YOUR-ENDPOINT> with the OSS endpoint, such as oss-cn-hangzhou.aliyuncs.com.
              public string Host { get; set; } = "<YOUR-BUCKET>.<YOUR-ENDPOINT>";
              // Specify the prefix for files to upload to OSS.
              public string UploadDir { get; set; } = "user-dir-prefix/";
              // Specify the expiration time in 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. The client uses the signature and POST policy to call the PostObject operation to upload the object to OSS by using an HTML form.

    The following JavaScript example demonstrates a browser-based file upload:

    <!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;
            // Request signature and policy from the application server
            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);
                // Append file to the form. File must be the last field in the form.
                formData.append('file', file);
                // POST the form data to OSS
                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>
    

Usage notes

Data security

Object overwriting

By default, OSS overwrites existing objects with the uploaded objects that have the same names. You can use the following methods to prevent existing objects from being unexpectedly overwritten:

  • Enable versioning for the bucket

    If you enable versioning for a bucket, objects that are overwritten in the bucket are saved as previous versions. You can restore the previous versions of the objects at any time. For more information, see Versioning.

  • Include the x-oss-forbid-overwrite parameter in the upload request

    You can add the x-oss-forbid-overwrite parameter to the form fields of the upload request and set this parameter to true. If you upload an object that has the same name as an existing object, the upload fails and the FileAlreadyExists error code is returned. If you do not add this parameter to the request or if you set this parameter to false, the uploaded object overwrites the existing object that has the same name in the bucket.

Authorized upload

  • OSS provides access control at the bucket and object levels to prevent unauthorized data uploads to your bucket by third parties. For more information, see Overview of permissions and access control.

  • You can use a signed URL to grant a third-party user permissions to upload a specific object. This way, the third-party user can upload data without access credentials or authorization. OSS stores the uploaded data as an object in the bucket. For more information, see Object uploads by using presigned URLs.

PUT request costs

Setting the storage class to Deep Cold Archive during upload incurs higher PUT request fees. We recommend that you set the storage classes of the objects to Standard when you upload the objects, and configure lifecycle rules to convert the storage classes of the Standard objects to Deep Cold Archive. This reduces PUT request fees.

Object upload to a bucket for which OSS-HDFS is enabled

To maintain OSS-HDFS stability and prevent data loss, do not upload objects to the .dlsdata/ directory of a bucket for which OSS-HDFS is enabled by using methods that are not supported by OSS-HDFS.

Upload performance tuning

If you upload a large number of objects and the names of the objects contain sequential prefixes such as timestamps and letters, multiple object indexes may be stored in a single partition. This can cause increased latency when querying these objects. If you want to upload a large number of objects, we recommend that you use random prefixes instead of sequential prefixes to specify object names. For more information, see OSS performance best practices.