All Products
Search
Document Center

Object Storage Service:Form upload

Last Updated:Jun 02, 2026

Form upload lets web applications upload objects directly to OSS through standard HTML forms. The browser sends a PostObject request to OSS without routing through your application server, which reduces server load and improves upload efficiency and stability.

Limits

Objects uploaded by using form upload cannot exceed 5 GB.

Scenarios

Common use cases for form upload:

  • User data upload: Upload avatars, ID photos, or identity verification materials during account registration or profile updates.

  • File sharing and storage: Upload documents, images, audio, and video to Alibaba Cloud through online drives or collaboration platforms.

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

  • E-commerce: Upload product images, descriptions, and qualification documents. Consumers upload invoices or supporting materials during purchases.

  • Online education: Students submit homework and projects. Teachers upload teaching materials and courseware.

  • Recruitment: Job seekers upload resumes and portfolios. Employers upload logos and job postings.

  • Surveys and feedback: Upload supporting documents or evidence with online questionnaires.

  • Development collaboration: Upload code files or project documents from platforms such as GitHub and GitLab.

How it works

The client obtains the signature and POST policy from the application server, then uploads objects directly without OSS SDKs. The POST policy can restrict object attributes such as size and type. Form upload does not support multipart upload or resumable upload. For more information, see PostObject.

Upload flow 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 the Post signature, Post Policy, and related information and returns them to the client.

  3. The client calls PostObject with the Post signature and Post Policy to upload the file to OSS through an HTML form.

  4. OSS returns a success response to the client.

Procedure

  1. The server generates the signature and POST policy.

    • Sample project: postsignature.zip

    • Examples

      Generate the Post signature and Post Policy on the server:

      Note

      Supports one-click deployment to 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
      
      # 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 calls the PostObject operation with the signature and POST policy to upload the object to OSS by using an HTML form.

    JavaScript example:

    <!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>
    

Usage notes

Data security

Object overwriting

By default, OSS overwrites existing objects with the same name. You can prevent unexpected overwrites by using the following methods:

  • Enable versioning for the bucket

    If versioning is enabled, overwritten objects are saved as previous versions that you can restore at any time. For more information, see Versioning.

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

    Add the x-oss-forbid-overwrite parameter to the form fields and set it to true. If an object with the same name exists, the upload fails with a FileAlreadyExists error. If this parameter is not included or is set to false, the uploaded object overwrites the existing one.

Authorized upload

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.

Buckets with OSS-HDFS enabled

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

Upload performance tuning

If object names contain sequential prefixes such as timestamps and letters, multiple indexes may be stored in a single partition, which increases query latency. Use random prefixes instead of sequential prefixes when uploading large volumes of objects. For more information, see OSS performance best practices.