Todos os produtos
Search
Central de documentação

Object Storage Service:Form upload

Última atualização: Sep 23, 2026

O form upload permite que aplicações web enviem objetos diretamente para o OSS por meio de formulários HTML padrão. O navegador envia uma requisição PostObject ao OSS sem passar pelo servidor da aplicação, reduzindo a carga no servidor e aumentando a eficiência e a estabilidade do upload.

Limites

Objetos enviados via form upload não podem exceder 5 GB.

Cenários

Casos de uso comuns para form upload:

  • Upload de dados do usuário: envie avatares, fotos de documentos ou materiais de verificação de identidade durante o cadastro de conta ou atualização de perfil.

  • Compartilhamento e armazenamento de arquivos: envie documentos, imagens, áudios e vídeos para a Alibaba Cloud por meio de drives online ou plataformas de colaboração.

  • Publicação de conteúdo: envie imagens e anexos em blogs, fóruns e plataformas de perguntas e respostas.

  • E-commerce: envie imagens de product, descrições e documentos de qualificação. Consumidores enviam notas fiscais ou materiais de suporte durante as compras.

  • Educação online: alunos enviam tarefas e projetos. Professores enviam materiais didáticos e conteúdos de aula.

  • Recrutamento: candidatos enviam currículos e portfólios. Empregadores enviam logotipos e descrições de vagas.

  • Pesquisas e feedback: envie documentos de suporte ou evidências junto a questionários online.

  • Colaboração em desenvolvimento: envie arquivos de código ou documentos de projeto a partir de plataformas como GitHub e GitLab.

  • Contorno de timeouts e limites de tamanho em plataformas de relay de terceiros: ao enviar objetos por uma plataforma de relay de terceiros, como Cloudflare CDN ou uma função serverless, você pode encontrar um erro de timeout 524 ou um limite de tamanho de objeto (por exemplo, 30 MB). Use o form upload do OSS para enviar objetos diretamente do cliente, contornando a camada de relay e evitando timeouts e restrições de tamanho. O servidor da aplicação gera a assinatura e a POST policy; o cliente usa um formulário HTML para enviar o objeto diretamente ao endpoint do OSS. Esse método suporta objetos de até 5 GB.

Como funciona

O cliente obtém a assinatura e a POST policy do servidor da aplicação e, em seguida, envia os objetos diretamente sem utilizar os SDKs do OSS. A POST policy pode restringir atributos do objeto, como tamanho e tipo. O form upload não suporta multipart upload nem upload retomável. Para mais informações, consulte PostObject.

Fluxo de upload usando uma assinatura Post e uma Post Policy:

image
  1. O cliente solicita a assinatura Post, a Post Policy e outras informações ao servidor da aplicação.

  2. O servidor da aplicação gera a assinatura Post, a Post Policy e as informações relacionadas e as retorna ao cliente.

  3. O cliente chama PostObject com a assinatura Post e a Post Policy para enviar o arquivo ao OSS por meio de um formulário HTML.

  4. O OSS retorna uma resposta de sucesso ao cliente.

Procedimento

  1. O servidor gera a assinatura e a POST policy.

    • Projeto de exemplo: postsignature.zip

    • Exemplos

      Gere a assinatura Post e a Post Policy no servidor:

      Nota

      Suporta implantação com um clique no 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. O cliente chama a operação PostObject com a assinatura e a POST policy para enviar o objeto ao OSS usando um formulário HTML.

    Exemplo em JavaScript:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Upload an object to OSS</title>
    </head>
    <body>
      <div class="container">
        <form>
          <div class="mb-3">
            <label for="file" class="form-label">Select the object</label>
            <input type="file" class="form-control" id="file" name="file" required>
          </div>
          <button type="submit" class="btn btn-primary">Upload</button>
        </form>
      </div>
      <script type="text/javascript">
          const form = document.querySelector('form');
          const fileInput = document.querySelector('#file');
          form.addEventListener('submit', (event) => {
            event.preventDefault();
            let file = fileInput.files[0];
            let filename = fileInput.files[0].name;
            fetch('/get_post_signature_for_oss_upload', { method: 'GET' })
              .then(response => response.json())
              .then(data => {
                const formData = new FormData();
                formData.append('name',filename);
                formData.append('policy', data.policy);
                formData.append('OSSAccessKeyId', data.ossAccessKeyId);
                formData.append('success_action_status', '200');
                formData.append('signature', data.signature);
                formData.append('key', data.dir + filename);
                // Set file to the last form field. No particular order is required for other form fields. 
                formData.append('file', file);
                fetch(data.host, { method: 'POST', body: formData},).then((res) => {
                  console.log(res);
                  alert ('Object Uploaded');
                });
              })
              .catch(error => {
                console.log('Error occurred while getting OSS upload parameters:', error);
              });
          });
      </script>
    </body>
    </html>
    

Notas de uso

Data security

Object overwriting

Por padrão, o OSS sobrescreve objetos existentes com o mesmo nome. Para evitar sobrescritas inesperadas, utilize os métodos a seguir:

  • Ative o versionamento no bucket

    Com o versionamento ativo, os objetos sobrescritos são salvos como versões anteriores, que podem ser restauradas a qualquer momento. Para mais informações, consulte Versioning.

  • Inclua o parâmetro x-oss-forbid-overwrite na requisição de upload

    Adicione o parâmetro x-oss-forbid-overwrite aos campos do formulário e defina-o como true. Se um objeto com o mesmo nome já existir, o upload falhará com o erro FileAlreadyExists. Caso este parâmetro não seja incluído ou seja definido como false, o objeto enviado substituirá o existente.

Authorized upload

  • O OSS oferece controle de acesso em nível de bucket e de objeto para impedir uploads não autorizados. Para mais informações, consulte Overview of permissions and access control.

  • Use uma URL assinada para permitir que um usuário terceiro envie um objeto específico sem credenciais de acesso. O OSS armazena os dados enviados como um objeto no bucket. Para mais informações, consulte Object uploads by using presigned URLs.

PUT request costs

Ao enviar um grande número de objetos, especificar diretamente a classe de armazenamento Deep Cold Archive resulta em taxas de requisição PUT elevadas. Recomenda-se especificar primeiro a classe de armazenamento Standard ao fazer o upload dos objetos e, em seguida, usar lifecycle rules para convertê-los para a classe Deep Cold Archive, reduzindo assim as taxas de requisição PUT.

Buckets with OSS-HDFS enabled

Para manter a estabilidade do OSS-HDFS e evitar perda de dados, não envie objetos para o diretório .dlsdata/ de um bucket com OSS-HDFS ativo usando métodos não suportados pelo OSS-HDFS.

Upload performance tuning

Quando os nomes dos objetos contêm prefixos sequenciais, como timestamps e letras, múltiplos índices podem ser armazenados em uma única partição, aumentando a latência das consultas. Use prefixos aleatórios em vez de sequenciais ao enviar grandes volumes de objetos. Para mais informações, consulte OSS performance best practices.