Todos los productos
Search
Centro de documentos

Object Storage Service:Use a presigned URL to handle object uploads

Última actualización: Sep 24, 2026

De forma predeterminada, la lista de control de acceso (ACL) de un objeto en un bucket de Object Storage Service (OSS) es privada. Esto significa que solo el propietario del objeto tiene permiso para acceder a él. Sin embargo, el propietario puede generar una URL prefirmada para otorgar acceso temporal a terceros y permitirles cargar objetos durante un periodo determinado. Esta función habilita escenarios como la carga de contratos por parte de socios o el envío de imágenes de perfil por parte de los usuarios.

Notas de uso

  • En este tema se utiliza el endpoint público de la región China (Hangzhou). Para acceder a OSS desde otros servicios de Alibaba Cloud en la misma región, utilice un endpoint interno. Para más información sobre las regiones y los endpoints compatibles, consulte Regions and endpoints.

  • No se requieren permisos para generar una URL prefirmada. No obstante, un tercero solo podrá cargar correctamente un archivo con dicha URL si usted cuenta con el permiso oss:PutObject. Para más información, consulte Grant a custom access policy to a RAM user.

  • Las URL prefirmadas no admiten cargas mediante FormData. Para cargas con FormData, utilice form uploads.

Flujo de trabajo

La siguiente figura muestra el proceso para cargar un objeto en OSS mediante una URL prefirmada.

image

Uso de una URL prefirmada para cargar un objeto

  1. El propietario del bucket genera una URL prefirmada que admite solicitudes PUT.

    Nota

    Una URL prefirmada generada con el SDK de OSS tiene un periodo de validez máximo de 7 días. Si genera la URL prefirmada mediante un token de Security Token Service (STS), esta puede ser válida hasta por 12 horas (43 200 segundos).

    Java

    Para obtener información sobre cómo usar el SDK de OSS para Java y generar una URL prefirmada, consulte OSS SDK for Java.

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;
    
    public class GetSignUrl {
        public static void main(String[] args) throws Throwable {
            // The public endpoint of China (Hangzhou) is used as an example. For other regions, replace the value with your actual information.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Retrieve access credentials from environment variables. Before running this code, ensure that environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET are set.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            //  Specify the bucket name, for example, "examplebucket".
            String bucketName = "examplebucket";
            // Specify the full path of the object, for example, "exampleobject.txt". The object path should not include the bucket name.
            String objectName = "exampleobject.txt";
            // Specify the region where the bucket is located. For example, if the bucket is in China (Hangzhou), set the region to cn-hangzhou.
            String region = "cn-hangzhou";
    
            // Create an OSSClient instance.
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            URL signedUrl = null;
            try {
                // Specify the validity period for the generated presigned URL in milliseconds. In this example, the expiration time is set to 1 hour.
                Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
    
                // Generate a presigned URL.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
                // Specify the expiration time of the presigned URL.
                request.setExpiration(expiration);
                // Generate a presigned URL that allows the HTTP PUT method.
                signedUrl = ossClient.generatePresignedUrl(request);
                // Display the presigned URL.
                System.out.println("signed url for putObject: " + signedUrl);
    
            } 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("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());
            }
        }
    }       

    Go

    Para obtener información sobre cómo usar el SDK de OSS para Go y generar una URL prefirmada, consulte OSS SDK for Go.

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // Define global variables.
    var (
    	region     string // The region of the bucket.
    	bucketName string // The name of the bucket.
    	objectName string // The name of the object.
    )
    
    //  Define the init function to initialize the command-line parameters.
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	// Parse the command-line parameters.
    	flag.Parse()
    
    	// Check whether the bucket name is empty.
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, bucket name required")
    	}
    
    	// Check whether the region is empty.
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// Check whether the object name is empty.
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, object name required")
    	}
    
    	// Load the default configuration and specify the credential provider and region.
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// Create an OSS client instance.
    	client := oss.NewClient(cfg)
    
    	// Generate a presigned URL with the PutObject method.
    	result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
    		Bucket: oss.Ptr(bucketName),
    		Key:    oss.Ptr(objectName),
    	},
    		oss.PresignExpires(10*time.Minute),
    	)
    	if err != nil {
    		log.Fatalf("failed to put object presign %v", err)
    	}
    
    	log.Printf("request method:%v\n", result.Method)
    	log.Printf("request expiration:%v\n", result.Expiration)
    	log.Printf("request url:%v\n", result.URL)
    	if len(result.SignedHeaders) > 0 {
    		//If the returned result contains signature headers, ensure you include these headers when making a PUT request with the presigned URL.
    		log.Printf("signed headers:\n")
    		for k, v := range result.SignedHeaders {
    			log.Printf("%v: %v\n", k, v)
    		}
    	}
    }
    

    Python

    Para obtener información sobre cómo usar el SDK de OSS para Python y generar una URL prefirmada, consulte OSS SDK for Python.

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # Create a command-line argument parser and describe the script's purpose: to generate a presigned PUT request URL for an object (Presign Put Object).
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # Define command-line arguments, including the required region, bucket name, endpoint, and object key.
    parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
    parser.add_argument('--bucket', help='The name of the bucket.', required=True)
    parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
    parser.add_argument('--key', help='The name of the object.', required=True)
    
    def main():
        # Parse command-line arguments to get user-provided values.
        args = parser.parse_args()
    
        # Load access credential information from environment variables for identity verification.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # Create a configuration object using the SDK's default settings and set the authentication provider.
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # Set the region property of the configuration object based on the command-line arguments.
        cfg.region = args.region
    
        # If a custom endpoint is provided, update the endpoint property in the configuration object.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # Initialize the OSS client with the above configuration to interact with OSS.
        client = oss.Client(cfg)
    
        # Send a request to generate a presigned PUT request for the specified object.
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket,  # Bucket name
            key=args.key,  # Object key
        ),expires=timedelta(seconds=3600)) # Set the expiration time in seconds. Here, it is set to 3600 seconds.
    
        # Print the method, expiration time, and URL of the presigned request to confirm the validity of the link.
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # Print the signed header information of the presigned request. This information will be included in the HTTP headers when the actual request is sent.
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # When this script is executed directly, call the main function to start the processing logic.
    if __name__ == "__main__":
        main()  # Script entry point. The program flow starts here.

    Node.js

    El siguiente ejemplo genera una URL prefirmada para cargas normales. Para obtener información sobre cómo usar el SDK de OSS para Node.js y generar una URL prefirmada con parámetros de procesamiento de imágenes o un identificador de versión, consulte OSS SDK for Node.js.

    const OSS = require("ali-oss");
    
    // Define a function to generate a signed URL.
    async function generateSignatureUrl(fileName) {
      // Obtain the presigned URL.
      const client = await new OSS({
          accessKeyId: 'yourAccessKeyId',
          accessKeySecret: 'yourAccessKeySecret',
          bucket: 'examplebucket',
          region: 'oss-cn-hangzhou',
          authorizationV4: true
      });
    
      return await client.signatureUrlV4('PUT', 3600, {
          headers: {} // Set the request headers based on the actual request headers.
      }, fileName);
    }
    // Call the function and pass the file name.
    generateSignatureUrl('yourFileName').then(url => {
      console.log('Generated Signature URL:', url);
    }).catch(err => {
      console.error('Error generating signature URL:', err);
    });

    PHP

    El siguiente ejemplo genera una URL prefirmada para cargas normales. Para obtener información sobre cómo usar el SDK de OSS para PHP y generar una URL prefirmada con un identificador de versión, consulte OSS SDK for PHP.

    <?php
    if (is_file(__DIR__ . '/../autoload.php')) {
        require_once __DIR__ . '/../autoload.php';
    }
    if (is_file(__DIR__ . '/../vendor/autoload.php')) {
        require_once __DIR__ . '/../vendor/autoload.php';
    }
    
    use OSS\OssClient;
    use OSS\Core\OssException;
    use OSS\Http\RequestCore;
    use OSS\Http\ResponseCore;
    use OSS\Credentials\EnvironmentVariableCredentialsProvider;
    
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
    $provider = new EnvironmentVariableCredentialsProvider();
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    $endpoint = "yourEndpoint";
    // Specify the name of the bucket. 
    $bucket= "examplebucket";
    // Specify the full path of the object. Do not include the bucket name in the full path of the object. 
    $object = "exampleobject.txt";
    // Set the validity period of the presigned URL to 600 seconds. Maximum value: 32400. 
    $timeout = 600;
    try {
        $config = array(  
            "provider" => $provider,
            "endpoint" => $endpoint,
            'signatureVersion'=>OssClient::OSS_SIGNATURE_VERSION_V4,
            "region"=> "cn-hangzhou"
        );
        $ossClient = new OssClient($config);
        // Generate the presigned URL. 
        $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT");
        print_r($signedUrl);
    } catch (OssException $e) {
        printf(__FUNCTION__ . ": FAILED\n");
        printf($e->getMessage() . "\n");
        return;
    }           

    Android

    Para obtener información sobre cómo usar el SDK de OSS para Android y generar una URL prefirmada, consulte Authorize access (Android SDK).

    // Specify the bucket name, for example, examplebucket.
    String bucketName = "examplebucket";
    // Specify the full path of the source object, without the bucket name, for example, exampleobject.txt.
    String objectKey = "exampleobject.txt";
    // Set the content-type.
    String contentType = "application/octet-stream";
    String url = null;
    try {
        // Generate a presigned URL for uploading the file.
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey);
        // Set the expiration time of the presigned URL to 30 minutes.
        request.setExpiration(30*60);
        request.setContentType(contentType);    
        request.setMethod(HttpMethod.PUT);
        url = oss.presignConstrainedObjectURL(request);
        Log.d("url", url);
    } catch (ClientException e) {
        e.printStackTrace();
    }

    C++

    Para obtener información sobre cómo usar el SDK de OSS para C++ y generar una URL prefirmada, consulte Authorize access (C++ SDK).

    #include <alibabacloud/oss/OssClient.h>
    using namespace AlibabaCloud::OSS;
    
    int main(void)
    {
        /* Initialize information about the account that is used to access OSS. */
                
        /* Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. */
        std::string Endpoint = "yourEndpoint";
        /* Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou.   * /
        std::string Region = "yourRegion";
        /* Specify the name of the bucket. Example: examplebucket. */
        std::string BucketName = "examplebucket";
        /* Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. */   
        std::string PutobjectUrlName = "exampledir/exampleobject.txt";
    
         /* Initialize resources, such as network resources. */
        InitializeSdk();
    
        ClientConfiguration conf;
        conf.signatureVersion = SignatureVersionType::V4;
        /* Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. */
        auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
        OssClient client(Endpoint, credentialsProvider, conf);
        client.SetRegion(Region);
    
        /* Specify the validity period of the pre-signed URL. The maximum validity period is 32,400. Unit: seconds. */
        std::time_t t = std::time(nullptr) + 1200;
        /* Generate a pre-signed URL. */
        auto genOutcome = client.GeneratePresignedUrl(BucketName, PutobjectUrlName, t, Http::Put);
        if (genOutcome.isSuccess()) {
            std::cout << "GeneratePresignedUrl success, Gen url:" << genOutcome.result().c_str() << std::endl;
        }
        else {
            /* Handle exceptions. */
            std::cout << "GeneratePresignedUrl fail" <<
            ",code:" << genOutcome.error().Code() <<
            ",message:" << genOutcome.error().Message() <<
            ",requestId:" << genOutcome.error().RequestId() << std::endl;
            return -1;
        }
    
        /* Release resources, such as network resources. */
        ShutdownSdk();
        return 0;
    }

    iOS

    Para obtener información sobre cómo usar el SDK de OSS para iOS y generar una URL prefirmada, consulte Authorize access (iOS SDK).

    // Specify the name of the bucket. 
    NSString *bucketName = @"examplebucket";
    // Specify the name of the object. 
    NSString *objectKey = @"exampleobject.txt";
    NSURL *file = [NSURL fileURLWithPath:@"<filePath>"];
    NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey];
    __block NSString *urlString;
    // Generate a presigned URL with a validity period for uploading the object. In this example, the validity period of the URL is 30 minutes. 
    OSSTask *task = [client presignConstrainURLWithBucketName:bucketName
                                                withObjectKey:objectKey
                                                   httpMethod:@"PUT"
                                       withExpirationInterval:30 * 60
                                               withParameters:@{}
                                                  contentType:contentType
                                                   contentMd5:nil];
    [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
        if (task.error) {
            NSLog(@"presign error: %@", task.error);
        } else {
            urlString = task.result;
            NSLog(@"url: %@", urlString);
        }
        return nil;
    }];

    .NET

    Para obtener información sobre cómo usar el SDK de OSS para .NET y generar una URL prefirmada, consulte Upload a file using a signed URL (C# SDK V1).

    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    // Specify the Endpoint for the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the Endpoint to https://oss-cn-hangzhou.aliyuncs.com.
    var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // Obtain access credentials from environment variables. Before you run this code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the bucket name, for example, examplebucket.
    var bucketName = "examplebucket";
    // Specify the full path of the object. The full path does not include the bucket name. For example, exampledir/exampleobject.txt.
    var objectName = "exampledir/exampleobject.txt";
    var objectContent = "More than just cloud.";
    // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the region to cn-hangzhou.
    const string region = "cn-hangzhou";
    
    // Create a ClientConfiguration instance and modify the default parameters as needed.
    var conf = new ClientConfiguration();
    
    // Set the signature version to V4.
    conf.SignatureVersion = SignatureVersion.V4;
    
    // Create an OssClient instance.
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
    client.SetRegion(region);
    try
    {
        // Generate a signed URL.
        var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put)
        {
            // Set the expiration time of the signed URL. The default value is 3600 seconds.
            Expiration = DateTime.Now.AddHours(1),
        };
        var signedUrl = client.GeneratePresignedUri(generatePresignedUriRequest);
    }
    catch (OssException ex)
    {
        Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
            ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Failed with error info: {0}", ex.Message);
    }

    C

    Para obtener información sobre cómo usar el SDK de OSS para C y generar una URL prefirmada, consulte Authorize access (C SDK).

    #include "oss_api.h"
    #include "aos_http_io.h"
    /* Set yourEndpoint to the endpoint of the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. */
    const char *endpoint = "yourEndpoint";
    
    /* Specify the bucket name. For example, examplebucket. */
    const char *bucket_name = "examplebucket";
    /* Specify the full path of the object. The full path cannot contain the bucket name. For example, exampledir/exampleobject.txt. */
    const char *object_name = "exampledir/exampleobject.txt";
    /* Specify the full path of the local file. */
    const char *local_filename = "yourLocalFilename";
    void init_options(oss_request_options_t *options)
    {
        options->config = oss_config_create(options->pool);
        /* Initialize the aos_string_t type with a char* string. */
        aos_str_set(&options->config->endpoint, endpoint);
        /* Obtain access credentials from environment variables. Before you run this sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set. */
        aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
        aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
        /* Specify whether to use a CNAME to access OSS. A value of 0 indicates that a CNAME is not used. */
        options->config->is_cname = 0;
        /* Set network parameters, such as the timeout period. */
        options->ctl = aos_http_controller_create(options->pool, 0);
    }
    int main(int argc, char *argv[])
    {
        /* Call the aos_http_io_initialize method at the program entry to initialize global resources, such as the network and memory. */
        if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
            exit(1);
        }
        /* The memory pool (pool) for memory management, which is equivalent to apr_pool_t. Its implementation code is in the APR library. */
        aos_pool_t *pool;
        /* Create a new memory pool. The second parameter is NULL, which indicates that the pool does not inherit from other memory pools. */
        aos_pool_create(&pool, NULL);
        /* Create and initialize options. This parameter includes global configuration information, such as endpoint, access_key_id, access_key_secret, is_cname, and curl. */
        oss_request_options_t *oss_client_options;
        /* Allocate memory for options in the memory pool. */
        oss_client_options = oss_request_options_create(pool);
        /* Initialize the client option oss_client_options. */
        init_options(oss_client_options);
        /* Initialize parameters. */
        aos_string_t bucket;
        aos_string_t object;
        aos_string_t file;    
        aos_http_request_t *req;
        apr_time_t now;
        char *url_str;
        aos_string_t url;
        int64_t expire_time; 
        int one_hour = 3600;
        aos_str_set(&bucket, bucket_name);
        aos_str_set(&object, object_name);
        aos_str_set(&file, local_filename);
        expire_time = now / 1000000 + one_hour;    
        req = aos_http_request_create(pool);
        req->method = HTTP_PUT;
        now = apr_time_now(); 
        /* Unit: microseconds. */
        expire_time = now / 1000000 + one_hour;
        /* Generate a presigned URL. */
        url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req);
        aos_str_set(&url, url_str);
        printf("Temporary upload URL: %s\n", url_str);    
        /* Release the memory pool. This is equivalent to releasing the memory allocated for various resources during the request. */
        aos_pool_destroy(pool);
        /* Release the previously allocated global resources. */
        aos_http_io_deinitialize();
        return 0;
    }
  1. Los demás usuarios cargan los objetos mediante la URL prefirmada al enviar una solicitud PUT.

    Importante

    Una URL prefirmada se puede utilizar varias veces antes de que caduque. Sin embargo, si se carga el mismo objeto en múltiples ocasiones, cada nueva carga sobrescribirá la anterior. Una vez que la URL caduca, el propietario debe generar una nueva URL prefirmada (como se muestra en Step 1) para que los demás mantengan el acceso.

Uso de URL prefirmadas para cargar un objeto por partes

Si necesita cargar objetos grandes, pero integrar un SDK de OSS en su cliente resulta difícil o imposible, considere usar cargas multiparte mediante URL prefirmadas. Con este enfoque, el servidor inicia el proceso de carga y asigna una URL prefirmada a cada parte. Así, su cliente o un servicio de terceros puede cargarlas de forma individual. Una vez que todas las partes se cargan correctamente, el servidor las combina en un objeto completo.

Importante

Cargar un objeto por partes con URL prefirmadas es más complejo que hacerlo con un SDK de OSS. Cuando utilice este método, asegúrese de que su cliente cargue la parte correspondiente al número especificado en la URL prefirmada. Si falta una parte o los números no coinciden, la combinación fallará. Si su cliente admite la integración del SDK de OSS, se recomienda usar client direct uploads basados en tokens de STS, ya que ofrecen mayor simplicidad y estabilidad.

image

  1. El cliente envía una solicitud de carga multiparte.

    El cliente envía una solicitud de carga multiparte que incluye el nombre del objeto, su tamaño y el tamaño de cada parte. El tamaño de cada parte tiene un máximo de 5 GB, aunque se recomienda un valor de 5 MB.

    A continuación se muestra un ejemplo de solicitud de carga multiparte enviada por el cliente. Al usarlo, recuerde reemplazar https://yourserver.com/init-upload con el endpoint de inicialización real de su servidor.

    curl -X POST https://yourserver.com/init-upload \
      -H "Content-Type: application/json" \
      -d '{
        "fileName": "exampleobject.jpg",
        "fileSize": 104857600,
        "partSize": 5242880
    }'
  2. El servidor inicia la carga multiparte y genera las URL prefirmadas.

    1. Llama a InitiateMultipartUpload para iniciar la carga y obtener el ID de carga.

    2. Calcula el número de partes según el tamaño del objeto y el tamaño de cada parte.

    3. Genera una URL prefirmada para cada parte.

    4. Devuelve una lista de URL prefirmadas en formato JSON.

    Nota

    El servidor registra el ID de carga, que identifica de forma única la carga multiparte y sirve para comprobar y combinar las partes. Puede almacenar este ID mediante caché, bases de datos u otros métodos.

    Código de ejemplo para iniciar una carga multiparte y generar URL prefirmadas

    Java

    import com.aliyun.oss.ClientBuilderConfiguration;
    import com.aliyun.oss.HttpMethod;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.InitiateMultipartUploadRequest;
    import com.aliyun.oss.model.InitiateMultipartUploadResult;
    
    import java.net.URL;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    public class InitAndGenerateURL {
        public static void main(String[] args) throws Throwable {
            // Simulate the client-provided file size and part size in bytes.
            long fileSize = 15 * 1024 * 1024L;   // Simulate a file size of 15 MB.
            long partSize = 5 * 1024 * 1024L;    // Simulate a part size of 5 MB.
    
            // Calculate the number of parts.
            int totalParts = (int) ((fileSize + partSize - 1) / partSize);
    
            // Specify the endpoint for accessing OSS. 
            // In this example, the endpoint for the China (Hangzhou) region is used.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            String region = "cn-hangzhou";
            String bucketName = "exampleBucket";
            String objectName = "exampleObject.jpeg";
            long expireTime = 3600 * 1000L; // Specify that the URL is valid for 1 hour.
    
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            ClientBuilderConfiguration config = new ClientBuilderConfiguration();
            config.setSignatureVersion(SignVersion.V4);
    
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .region(region)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(config)
                    .build();
    
            // Initiate a multipart upload.
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
            InitiateMultipartUploadResult initResult = ossClient.initiateMultipartUpload(initRequest);
            String uploadId = initResult.getUploadId();
            System.out.println("Upload ID: " + uploadId);
            System.out.println("Total parts: " + totalParts);
    
            // Generate a presigned URL for each part.
            for (int i = 1; i <= totalParts; i++) {
                Map<String, String> headers = new HashMap<>();
                String signedUrl = generatePresignedUrl(ossClient, bucketName, objectName, HttpMethod.PUT,
                        expireTime, i, uploadId, headers);
                System.out.println("Part " + i + " URL: " + signedUrl);
            }
    
            ossClient.shutdown();
        }
    
        public static String generatePresignedUrl(OSS ossClient, String bucketName, String objectName, HttpMethod method,
                                                  long expireTime, int partNum, String uploadId, Map<String, String> headers) {
            Date expiration = new Date(System.currentTimeMillis() + expireTime);
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, method);
            request.setExpiration(expiration);
            request.setHeaders(headers);
            request.addQueryParameter("partNumber", String.valueOf(partNum));
            request.addQueryParameter("uploadId", uploadId);
            URL url = ossClient.generatePresignedUrl(request);
            return url.toString();
        }
    }
    

    Go

    package main
    
    import (
    	"context"
    	"encoding/json"
    	"flag"
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    type SignedPart struct {
    	PartNumber int    `json:"part_number"`
    	URL        string `json:"url"`
    	Method     string `json:"method"`
    }
    
    type UploadInitResponse struct {
    	UploadId string       `json:"upload_id"`
    	Parts    []SignedPart `json:"parts"`
    }
    
    // Define global variables.
    var (
    	region     string
    	bucketName string
    	objectName string
    )
    
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	flag.Parse()
    
    	// Assume that the file size is 15 MB and that the part size is 5 MB.
    	fileSize := int64(15 * 1024 * 1024)
    	partSize := int64(5 * 1024 * 1024)
    	totalParts := int((fileSize + partSize - 1) / partSize)
    
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	client := oss.NewClient(cfg)
    
    	// Initiate a multipart upload.
    	resp, err := client.InitiateMultipartUpload(context.TODO(), &oss.InitiateMultipartUploadRequest{
    		Bucket: oss.Ptr(bucketName),
    		Key:    oss.Ptr(objectName),
    	})
    	if err != nil {
    		log.Fatalf("Failed to initiate multipart upload: %v", err)
    	}
    	uploadId := resp.UploadId
    	fmt.Println("Upload ID:", *uploadId)
    	fmt.Println("Total parts:", totalParts)
    
    	// Generate a presigned URL for each part.
    	expire := time.Hour // Set the validity period of the presigned URL to 1 hour.
    	var parts []SignedPart
    	for i := 1; i <= totalParts; i++ {
    		req := &oss.UploadPartRequest{
    			Bucket:     oss.Ptr(bucketName),
    			Key:        oss.Ptr(objectName),
    			PartNumber: int32(i),
    			UploadId:   uploadId,
    		}
    		presignResult, err := client.Presign(context.TODO(), req, oss.PresignExpiration(time.Now().Add(expire)))
    		if err != nil {
    			log.Fatalf("Failed to generate signed URL for part %d: %v", i, err)
    		}
    		parts = append(parts, SignedPart{
    			PartNumber: i,
    			URL:        presignResult.URL,
    			Method:     "PUT",
    		})
    	}
    
    	// Display response in JSON.
    	out := UploadInitResponse{
    		UploadId: *uploadId,
    		Parts:    parts,
    	}
    	outJSON, _ := json.MarshalIndent(out, "", "  ")
    	fmt.Println(string(outJSON))
    }
    

    Python

    import argparse
    import json
    import alibabacloud_oss_v2 as oss
    
    # Stimulate parameters.
    FILE_SIZE = 15 * 1024 * 1024  # Stimulate a file size of 15 MB.
    PART_SIZE = 5 * 1024 * 1024   # Stimulate a part size of 5 MB.
    EXPIRE_TIME = 3600            # Stimulate a URL validity period of 3,600 seconds.
    
    def main():
        # Create a command-line argument parser and describe the purpose of the script.
        parser = argparse.ArgumentParser(description="presign multipart upload sample")
    
        # Add the --region argument to specify the region of the bucket. This argument is required.
        parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
        # Add the --bucket argument to specify the bucket. This argument is required.
        parser.add_argument('--bucket', help='The name of the bucket.', required=True)
        # Add the --endpoint argument to specify the endpoint for accessing OSS. This argument is optional.
        parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
        # Add the --key argument to specify the name of the object. This argument is required.
        parser.add_argument('--key', help='The name of the object.', required=True)
    
        args = parser.parse_args()
    
        # Create a configuration for initializing an OSS client.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
        cfg.region = args.region
        # If an endpoint is provided, use it.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
        
        # Initialize an OSS client.
        client = oss.Client(cfg)
    
        # Send a multipart upload initiation request and get the upload ID.
        init_result = client.presign(oss.InitiateMultipartUploadRequest(
            bucket=args.bucket,
            key=args.key,
        ))
    
        # Use the presingned URL to initiate the upload and get the upload ID.
        import requests
        with requests.post(init_result.url, headers=init_result.signed_headers) as resp:
            obj = oss.InitiateMultipartUploadResult()
            oss.serde.deserialize_xml(xml_data=resp.content, obj=obj)
            upload_id = obj.upload_id
    
        # Calculate the number of parts and generate a presigned URL for each part.
        total_parts = (FILE_SIZE + PART_SIZE - 1) // PART_SIZE
        parts = []
    
        for part_number in range(1, total_parts + 1):
            req = oss.UploadPartRequest(
                bucket=args.bucket,
                key=args.key,
                part_number=part_number,
                upload_id=upload_id,
                expiration_in_seconds=EXPIRE_TIME
            )
            presign_result = client.presign(req)
            parts.append({
                "part_number": part_number,
                "url": presign_result.url,
                "method": "PUT"
            })
    
        # Display the upload ID and presigned URLs of all the parts in JSON.
        output = {
            "upload_id": upload_id,
            "parts": parts
        }
    
        print(json.dumps(output, indent=2))
    
    if __name__ == "__main__":
        main()
  3. El cliente carga el objeto por partes.

    El cliente envía solicitudes PUT para cargar cada parte de forma individual mediante las URL prefirmadas que devuelve el servidor. Cada parte se carga igual que en uploading an object with a presigned URL. Una vez cargadas todas las partes, el cliente notifica al servidor para que las combine.

    Nota

    Las cargas multiparte mediante URL prefirmadas admiten procesamiento concurrente. Sin embargo, es fundamental garantizar que cada URL se use exclusivamente para la parte designada. Por ejemplo, si la URL indica el número de parte N, debe usarse para cargar la enésima parte del archivo. No se permite reutilizar ni omitir números de parte.

    El siguiente comando de ejemplo carga la primera parte (/path/to/local/file es la ruta del archivo local):

    curl -X PUT -T /path/to/local/file "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.jpg?partNumber=1\u0026uploadId=BE2D0BC931BE4DE1B23F339AABFA49EE\u0026x-oss-credential=LTAI********************%2F20250520%2Fcn-hangzhou%2Foss%2Faliyun_v4_request\u0026x-oss-date=20250520T082728Z\u0026x-oss-expires=3600\u0026x-oss-signature=81f3d2e5eaa67c432291577ed20af3b3f60df05ab3cddedcdce168ef707f7ad0\u0026x-oss-signature-version=OSS4-HMAC-SHA256"
  4. (Opcional) El servidor comprueba las partes cargadas.

    De manera opcional, configure el servidor para que compruebe las partes cargadas cuando reciba la notificación de finalización.

    • Compruebe la integridad de las partes cargadas.

    • Verifique que cada parte tenga el tamaño esperado.

    Nota

    La comprobación de las partes requiere el ID de carga registrado previamente.

    Código de ejemplo para comprobar las partes

    Java

    import com.aliyun.oss.ClientBuilderConfiguration;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.*;
    
    import java.util.ArrayList;
    import java.util.List;
    public class complete {
    
        public static void main(String[] args) throws Exception {
            // Specify the endpoint for the region of your bucket. In this example, it is the endpoint for the China (Hangzhou) region.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Specify the name of the bucket.
            String bucketName = "examplebucket";
            // Specify the full path of the object. Do not include the bucket name in the full path.
            String objectName = "exampleobject.jpeg";
            // Specify the upload ID.
            String uploadId = "4B78****************************";
            // Specify the ID of the region of the bucket.
            String region = "cn-hangzhou";
    
            // Use credentials stored in environment variables to create an OSS client.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            ClientBuilderConfiguration config = new ClientBuilderConfiguration();
            config.setSignatureVersion(SignVersion.V4);
    
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .region(region)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(config)
                    .build();
    
            try {
                // List all parts that have been uploaded in the multipart upload.
                ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);
                PartListing partListing = ossClient.listParts(listPartsRequest);
    
                // Collect the ETags of parts. ETags will be used for part combination later.
                List<PartETag> partETags = new ArrayList<>();
                for (PartSummary part : partListing.getParts()) {
                    partETags.add(new PartETag(part.getPartNumber(), part.getETag()));
                }
    
                if (partETags.isEmpty()) {
                    System.out.println("No uploaded parts. The operation stopped.");
                    return;
                }
    
                // Combine parts.
                System.out.println("Combining parts...");
                CompleteMultipartUploadRequest completeRequest =
                        new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
    
                CompleteMultipartUploadResult result = ossClient.completeMultipartUpload(completeRequest);
                System.out.println("Parts combined.");
                System.out.println("ETag: " + result.getETag());
    
            } catch (Exception e) {
                System.err.println("Part combination failed: " + e.getMessage());
                e.printStackTrace();
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
    }
    

    Go

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    var (
    	region     string
    	bucketName string
    	objectName string
    	uploadId   string
    )
    
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    	flag.StringVar(&uploadId, "uploadId", "", "The upload ID.")
    }
    
    func main() {
    	flag.Parse()
    
    	if region == "" || bucketName == "" || objectName == "" || uploadId == "" {
    		flag.PrintDefaults()
    		log.Fatal("Missing required parameters.")
    	}
    
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	client := oss.NewClient(cfg)
    
    	// List uploaded parts.
    	partListResp, err := client.ListParts(context.TODO(), &oss.ListPartsRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    	})
    	if err != nil {
    		log.Fatalf("failed to list parts: %v", err)
    	}
    
    	var parts []oss.UploadPart
    	for _, p := range partListResp.Parts {
    		parts = append(parts, oss.UploadPart{
    			PartNumber: p.PartNumber,
    			ETag:       p.ETag,
    		})
    	}
    
    	// Combine uploaded parts.
    	completeResult, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
    			Parts: parts,
    		},
    	})
    	if err != nil {
    		log.Fatalf("failed to complete multipart upload: %v", err)
    	}
    
    	// Display the combination result.
    	log.Println("Upload completed successfully.")
    	log.Printf("Bucket:   %s\n", oss.ToString(completeResult.Bucket))
    	log.Printf("Key:      %s\n", oss.ToString(completeResult.Key))
    	log.Printf("ETag:     %s\n", oss.ToString(completeResult.ETag))
    	log.Printf("Status:   %s\n", completeResult.Status)
    }
    

    Python

    # -*- coding: utf-8 -*-
    import argparse
    import alibabacloud_oss_v2 as oss
    
    def main():
        # Create a command-line argument parse and describe the purpose of the script.
        parser = argparse.ArgumentParser(description="presign multipart upload sample")
        # Add the --region argument to specify the region of the bucket. This argument is required.
        parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
        # Add the --bucket argument to specify the bucket. This argument is required.
        parser.add_argument('--bucket', help='The name of the bucket.', required=True)
        # Add the --endpoint argument to specify the endpoint for accessing OSS. This argument is optional.
        parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
        # Add the --key argument to specify the name of the object. This argument is required.
        parser.add_argument('--key', help='The name of the object.', required=True)
        # Add the --upload_id argument to specify the upload ID. This argument is required.
        parser.add_argument('--upload_id', help='The upload ID to list parts for.',required=True)
    
        args = parser.parse_args()
    
        # Specify the configuration and credentials for initializing an OSS client.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
        cfg.region = args.region
        if args.endpoint:
            cfg.endpoint = args.endpoint
    
        client = oss.Client(cfg)
    
        try:
            # List all uploaded parts.
            list_parts_result = client.list_parts(oss.ListPartsRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id
            ))
    
            # Construct a list of uploaded parts.
            upload_parts = [
                oss.UploadPart(part_number=part.part_number, etag=part.etag)
                for part in list_parts_result.parts
            ]
    
            if not upload_parts:
                print("No uploaded parts found. The operation stopped.")
                return
    
            # Construct and execute a part combination request.
            request = oss.CompleteMultipartUploadRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id,
                complete_multipart_upload=oss.CompleteMultipartUpload(parts=upload_parts)
            )
    
            result = client.complete_multipart_upload(request)
    
            print("Parts combined.")
            print(f"ETag: {result.etag}")
            print(f"Bucket: {result.bucket}")
            print(f"Key: {result.key}")
    
        except Exception as e:
            print("Part combination failed:", e)
    
    if __name__ == "__main__":
        main()
  5. El servidor combina las partes y devuelve el resultado de la carga.

    Una vez superada la comprobación, el servidor llama a la operación CompleteMultipartUpload para combinar las partes en un objeto completo. Después, devuelve el resultado de la carga al cliente.

    Código de ejemplo para combinar las partes

    Java

    import com.aliyun.oss.ClientBuilderConfiguration;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.model.*;
    
    import java.util.ArrayList;
    import java.util.List;
    public class complete {
    
        public static void main(String[] args) throws Exception {
            // Specify the endpoint for the region of your bucket. In this example, it is the endpoint for the China (Hangzhou) region.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Specify the name of your bucket.
            String bucketName = "examplebucket";
            // Specify the full path of your object. Do not include the bucket name in the full path.
            String objectName = "exampleobject.jpeg";
            // Specify the upload ID.
            String uploadId = "4B78****************************";
            // Specify the ID of the region of your bucket.
            String region = "cn-hangzhou";
    
            // Use credentials stored in environment variables to create an OSS client.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            ClientBuilderConfiguration config = new ClientBuilderConfiguration();
            config.setSignatureVersion(SignVersion.V4);
    
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .region(region)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(config)
                    .build();
    
            try {
                // List all parts that have been uploaded in the multipart upload.
                ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);
                PartListing partListing = ossClient.listParts(listPartsRequest);
    
                // Collect the ETags of parts. ETags will be used for part combination later.
                List<PartETag> partETags = new ArrayList<>();
                for (PartSummary part : partListing.getParts()) {
                    partETags.add(new PartETag(part.getPartNumber(), part.getETag()));
                }
    
                if (partETags.isEmpty()) {
                    System.out.println("No uploaded parts. The operation stopped.");
                    return;
                }
    
                // Combine parts.
                System.out.println("Combining parts...");
                CompleteMultipartUploadRequest completeRequest =
                        new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
    
                CompleteMultipartUploadResult result = ossClient.completeMultipartUpload(completeRequest);
                System.out.println("Parts combined.");
                System.out.println("ETag: " + result.getETag());
    
            } catch (Exception e) {
                System.err.println("Part combination failed: " + e.getMessage());
                e.printStackTrace();
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
    }
    

    Go

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    var (
    	region     string
    	bucketName string
    	objectName string
    	uploadId   string
    )
    
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    	flag.StringVar(&uploadId, "uploadId", "", "The upload ID.")
    }
    
    func main() {
    	flag.Parse()
    
    	if region == "" || bucketName == "" || objectName == "" || uploadId == "" {
    		flag.PrintDefaults()
    		log.Fatal("Missing required parameters.")
    	}
    
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	client := oss.NewClient(cfg)
    
    	// List uploaded parts.
    	partListResp, err := client.ListParts(context.TODO(), &oss.ListPartsRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    	})
    	if err != nil {
    		log.Fatalf("failed to list parts: %v", err)
    	}
    
    	var parts []oss.UploadPart
    	for _, p := range partListResp.Parts {
    		parts = append(parts, oss.UploadPart{
    			PartNumber: p.PartNumber,
    			ETag:       p.ETag,
    		})
    	}
    
    	// Combine uploaded parts.
    	completeResult, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
    		Bucket:   oss.Ptr(bucketName),
    		Key:      oss.Ptr(objectName),
    		UploadId: oss.Ptr(uploadId),
    		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
    			Parts: parts,
    		},
    	})
    	if err != nil {
    		log.Fatalf("failed to complete multipart upload: %v", err)
    	}
    
    	// Display the combination result.
    	log.Println("Upload completed successfully.")
    	log.Printf("Bucket:   %s\n", oss.ToString(completeResult.Bucket))
    	log.Printf("Key:      %s\n", oss.ToString(completeResult.Key))
    	log.Printf("ETag:     %s\n", oss.ToString(completeResult.ETag))
    	log.Printf("Status:   %s\n", completeResult.Status)
    }
    

    Python

    # -*- coding: utf-8 -*-
    import argparse
    import alibabacloud_oss_v2 as oss
    
    def main():
        # Create a command-line argument parse and describe the purpose of the script.
        parser = argparse.ArgumentParser(description="presign multipart upload sample")
        # Add the --region argument to specify the region of the bucket. This argument is required.
        parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
        # Add the --bucket argument to specify the bucket. This argument is required.
        parser.add_argument('--bucket', help='The name of the bucket.', required=True)
        # Add the --endpoint argument to specify the endpoint for accessing OSS. This argument is optional.
        parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
        # Add the --key argument to specify the name of the object. This argument is required.
        parser.add_argument('--key', help='The name of the object.', required=True)
        # Add the --upload_id argument to specify the upload ID. This argument is required.
        parser.add_argument('--upload_id', help='The upload ID to list parts for.',required=True)
    
        args = parser.parse_args()
    
        # Specify the configuration and credentials for initializing an OSS client.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
        cfg.region = args.region
        if args.endpoint:
            cfg.endpoint = args.endpoint
    
        client = oss.Client(cfg)
    
        try:
            # List all uploaded parts.
            list_parts_result = client.list_parts(oss.ListPartsRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id
            ))
    
            # Construct a list of uploaded parts.
            upload_parts = [
                oss.UploadPart(part_number=part.part_number, etag=part.etag)
                for part in list_parts_result.parts
            ]
    
            if not upload_parts:
                print("No uploaded parts found. The operation stopped.")
                return
    
            # Construct and execute a part combination request.
            request = oss.CompleteMultipartUploadRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=args.upload_id,
                complete_multipart_upload=oss.CompleteMultipartUpload(parts=upload_parts)
            )
    
            result = client.complete_multipart_upload(request)
    
            print("Parts combined.")
            print(f"ETag: {result.etag}")
            print(f"Bucket: {result.bucket}")
            print(f"Key: {result.key}")
    
        except Exception as e:
            print("Part combination failed:", e)
    
    if __name__ == "__main__":
        main()

Configuración de encabezados para especificar la política de carga

Al generar una URL prefirmada, puede definir una política de carga mediante el parámetro Header. Por ejemplo, establezca encabezados como x-oss-storage-class (para definir la clase de almacenamiento) y Content-Type (para especificar el tipo de objeto).

Importante

Si incluye encabezados al generar la URL prefirmada, debe proporcionar los mismos encabezados al cargar el objeto. Si los encabezados no coinciden, OSS devuelve un error 403 debido a un fallo en la verificación de la firma.

Para obtener información sobre los encabezados compatibles, consulte PutObject. También puede configurar encabezados personalizados para gestionar los metadatos del objeto. Para más información, consulte Manage object metadata.

  1. El propietario del objeto genera una URL prefirmada con el parámetro Header.

    Java

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.StorageClass;
    
    import java.net.URL;
    import java.util.*;
    import java.util.Date;
    
    public class GetSignUrl {
        public static void main(String[] args) throws Throwable {
            // This example uses the public endpoint of the China (Hangzhou) region. Specify the actual endpoint.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Specify the bucket name, for example, examplebucket.
            String bucketName = "examplebucket";
            // Specify the full path of the object, for example, exampleobject.txt. The full path of the object cannot contain the bucket name.
            String objectName = "exampleobject.txt";
            // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the region to cn-hangzhou.
            String region = "cn-hangzhou";
    
            // Create an OSSClient instance.
            // When the OSSClient instance is no longer in use, call the shutdown method to release resources.
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            // Set the request headers.
            Map<String, String> headers = new HashMap<String, String>();
            // Specify the StorageClass.
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            // Specify the ContentType.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain; charset=utf8");
    
            // Set the custom user metadata.
            Map<String, String> userMetadata = new HashMap<String, String>();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            URL signedUrl = null;
            try {
                // Specify the expiration time of the generated presigned URL in milliseconds. This example sets the expiration time to 1 hour.
                Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
    
                // Generate a presigned URL.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
                // Set the expiration time.
                request.setExpiration(expiration);
    
                // Add the request headers to the request.
                request.setHeaders(headers);
                // Add the custom user metadata.
                request.setUserMetadata(userMetadata);
    
                // Generate a presigned URL for an HTTP PUT request.
                signedUrl = ossClient.generatePresignedUrl(request);
                // Print the presigned URL.
                System.out.println("signed url for putObject: " + signedUrl);
    
            } 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("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());
            }
        }
    }       

    Go

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // Define global variables
    var (
    	region     string // Storage region
    	bucketName string // Bucket name
    	objectName string // Object name
    )
    
    // The init function initializes command-line parameters
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	// Parse command-line parameters
    	flag.Parse()
    
    	// Check whether the bucket name is empty
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, bucket name required")
    	}
    
    	// Check whether the region is empty
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// Check whether the object name is empty
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, object name required")
    	}
    
    	// Load the default configuration and set the credential provider and region
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// Create an OSS client
    	client := oss.NewClient(cfg)
    
    	// Generate a presigned URL for PutObject
    	result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
    		Bucket:      oss.Ptr(bucketName),
    		Key:         oss.Ptr(objectName),
    		ContentType:  oss.Ptr("text/plain;charset=utf8"),                    // Make sure that the ContentType specified when generating the presigned URL on the server is the same as the ContentType specified when using the URL
    		StorageClass: oss.StorageClassStandard,                              // Make sure that the StorageClass specified when generating the presigned URL on the server is the same as the StorageClass specified when using the URL
    		Metadata:    map[string]string{"key1": "value1", "key2": "value2"}, // Make sure that the Metadata specified when generating the presigned URL on the server is the same as the Metadata specified when using the URL
    	},
    		oss.PresignExpires(10*time.Minute),
    	)
    	if err != nil {
    		log.Fatalf("failed to put object presign %v", err)
    	}
    
    	log.Printf("request method:%v\n", result.Method)
    	log.Printf("request expiration:%v\n", result.Expiration)
    	log.Printf("request url:%v\n", result.URL)
    	if len(result.SignedHeaders) > 0 {
    		// If the returned result contains signature headers, set the corresponding request headers when sending a PUT request by using the presigned URL
    		log.Printf("signed headers:\n")
    		for k, v := range result.SignedHeaders {
    			log.Printf("%v: %v\n", k, v)
    		}
    	}
    }
    

    Python

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # Create a command-line argument parser and describe the script's purpose: to generate a presigned PUT request URL for an object (Presign Put Object).
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # Define command-line arguments, including the required region, bucket name, endpoint, and object key.
    parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
    parser.add_argument('--bucket', help='The name of the bucket.', required=True)
    parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
    parser.add_argument('--key', help='The name of the object.', required=True)
    
    def main():
        # Parse command-line arguments to get user-provided values.
        args = parser.parse_args()
    
        # Load access credential information from environment variables for identity verification.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # Create a configuration object using the SDK's default settings and set the authentication provider.
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # Set the region property of the configuration object based on the command-line arguments.
        cfg.region = args.region
    
        # If a custom endpoint is provided, update the endpoint property in the configuration object.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # Initialize the OSS client with the above configuration to interact with OSS.
        client = oss.Client(cfg)
    
        # Send a request to generate a presigned PUT request for the specified object.
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket,  # Bucket name
            key=args.key,  # Object key
            content_type='text/plain;charset=utf8',  # Specify the content type.
            storage_class='Standard',  # Specify the storage class.
            metadata={
                'key1': 'value1',   # Specify the metadata.
                'key2': 'value2'    # Specify the metadata.
            }
        ),expires=timedelta(seconds=3600)) # Set the expiration time in seconds. Here, it is set to 3600 seconds.
    
        # Print the method, expiration time, and URL of the presigned request to confirm the validity of the link.
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # Print the signed header information of the presigned request. This information will be included in the HTTP headers when the actual request is sent.
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # When this script is executed directly, call the main function to start the processing logic.
    if __name__ == "__main__":
        main()  # Script entry point. The program flow starts here.
  2. Otros usuarios cargan los objetos mediante la URL prefirmada y proporcionan los mismos encabezados.

    curl

    curl -X PUT \
         -H "Content-Type: text/plain;charset=utf8" \
         -H "x-oss-storage-class: Standard" \
         -H "x-oss-meta-key1: value1" \
         -H "x-oss-meta-key2: value2" \
         -T "C:\\Users\\demo.txt" \
         "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"

    Java

    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.StorageClass;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.entity.FileEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.net.URL;
    import java.util.*;
    
    public class SignUrlUpload {
        public static void main(String[] args) throws Throwable {
            CloseableHttpClient httpClient = null;
            CloseableHttpResponse response = null;
    
            // Replace  with the signed URL.
            URL signedUrl = new URL("");
    
            // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs.
            String pathName = "C:\\Users\\demo.txt";
    
            // Specify request headers. Make sure that the values of the request headers are the same as that of the request headers when the signed URL is generated.
            Map headers = new HashMap();
            //Specify the storage class.
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            //Specify the content type.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated.
            Map userMetadata = new HashMap();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // If you configure headers such as the user metadata and storage class when the presigned URL was generated, these headers must be sent to the server when the presigned URL is used to upload a file. If the headers that are sent to the server for the signature calculation are inconsistent with those specified when the presigned URL was generated, a signature error is reported.
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
                for(Map.Entry meta: userMetadata.entrySet()){
                    // If user metadata is specified, the SDK adds the "x-oss-meta-" prefix to the user metadata key. If you use other methods to upload a file, make sure that the "x-oss-meta-" prefix is also added to the user metadata key.
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Status code of the upload: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the network library");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error {
    	// Open the local file
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Read the object content
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// Create a request
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// Specify request headers
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// Specify user metadata
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// Send the request
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// Process the response
    	fmt.Printf("Status code: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("The object is uploaded by using the network library")
    	} else {
    		fmt.Println("Upload failed")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace  with the signed URL.
    	signedUrl := ""
    
    	// Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs.
    	filePath := "C:\\Users\\demo.txt"
    
    	// Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
    	headers := map[string]string{
    		"Content-Type": "text/plain;charset=utf8",
    		"x-oss-storage-class": "Standard",
    	}
    
    	// Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated.
    	metadata := map[string]string{
    		"key1": "value1",
    		"key2": "value2",
    	}, headers, metadata)
    	if err != nil {
    		fmt.Printf("An error occurred: %v\n", err)
    	}
    }
    

    Python

    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        Use a pre-signed URL to upload an object to OSS.
    
        :param signed_url: the presigned URL.
        :param file_path: the full path of the local file that you want to upload.
        :param headers: Optional. Specify the request headers.
        :param metadata: user metadata. This parameter is optional.
        :return: None
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # Add the x-oss-meta- prefix to the metadata key.
        for key, value in metadata.items():
            headers[f'x-oss-meta-{key}'] = value
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"Status code: {response.status_code}")
                if response.status_code == 200:
                    print("The object is uploaded by using the network library")
                else:
                    print("Upload failed")
                print(response.text)
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # Replace  with the signed URL.
        signed_url = ""
       
        # Specify the full path of the local file. By default, if you do not specify the full path of a local file, the local file is uploaded from the directory in which the script is stored.
        file_path = "C:\\Users\\demo.txt"
    
        # Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
        headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        }
    
        # Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated.
        metadata = {
             "key1": "value1",
             "key2": "value2"
        }
    
        upload_file(signed_url, file_path, headers, metadata)
    

    Node.js

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // Update the request headers and specify the metadata prefix.
            for (const [key, value] of Object.entries(metadata)) {
                headers[`x-oss-meta-${key}`] = value;
            }
    
            // Read the file stream
            const fileStream = fs.createReadStream(filePath);
    
            // Send a PUT request
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`Status code: ${response.status}`);
            if (response.status === 200) {
                console.log("The object is uploaded by using the network library");
            } else {
                console.log("Upload failed");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // Specify the main function
    (async () => {
        // Replace  with the signed URL.
        const signedUrl = "";
    
        // Specify the full path of the local file. By default, if you do not specify the full path of a local file, the local file is uploaded from the directory in which the script is stored.
        const filePath = "C:\\Users\\demo.txt";
    
        // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // Specify user metadata. Make sure that the user metadata is the same as the user metadata when the signed URL is generated.
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    Importante

    Cuando utiliza código de Browser.js para cargar un objeto mediante una URL prefirmada, es posible que reciba un error 403 por inconsistencia de firma. Este error se produce porque el navegador agrega automáticamente el encabezado de solicitud Content-Type, el cual no se especificó al generar la URL prefirmada. Para resolverlo, especifique el encabezado Content-Type cuando genere una URL prefirmada destinada a usarse en código de Browser.js para cargar datos en OSS.

    C++

    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    #include <map>
    #include <string>
    
    // Callback function that is used to process the HTTP response
    size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append((char*)contents, totalSize);
        return totalSize;
    }
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) {
        CURL* curl;
        CURLcode res;
        std::string readBuffer;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // Specify the signed URL
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // Set the request method to PUT
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // Open the local file
            FILE* file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Unable to open the local file: " << filePath << std::endl;
                return;
            }
    
            // Specify the size of the local file
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // Configure a file read callback
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Specify request headers
            struct curl_slist* chunk = nullptr;
            for (const auto& header : headers) {
                std::string headerStr = header.first + ": " + header.second;
                chunk = curl_slist_append(chunk, headerStr.c_str());
            }
            for (const auto& meta : metadata) {
                std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second;
                chunk = curl_slist_append(chunk, metaStr.c_str());
            }
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    
            // Specify the callback function that is used to process the response
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
    
            // Execute the request
            res = curl_easy_perform(curl);
    
            // Check the response
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "Upload status code: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "The object is uploaded by using the network library." << std::endl;
                } else {
                    std::cout << "Upload failed." << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // Clean up
            fclose(file);
            curl_slist_free_all(chunk);
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // Replace <signedUrl> with the presigned URL.
        std::string signedUrl = "<signedUrl>";
    
        // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs.
        std::string filePath = "C:\\Users\\demo.txt";
    
        // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
        std::map<std::string, std::string> headers = {
             {"Content-Type", "text/plain;charset=utf8"},
             {"x-oss-storage-class", "Standard"}
        };
    
        // Specify user metadata. Make sure that the user metadata here is the same as the user metadata specified when the presigned URL was generated.
        std::map<std::string, std::string> metadata = {
             {"key1", "value1"},
             {"key2", "value2"}
        };
    
        uploadFile(signedUrl, filePath, headers, metadata);
    
        return 0;
    }
    

    C

    A diferencia del ejemplo de C++, que depende de std::string y de <iostream>/<fstream> (por lo que requiere un compilador de C++), el siguiente ejemplo está escrito en C estándar. Utiliza char*, <stdio.h> y libcurl, de modo que se compila y ejecuta con una cadena de herramientas básica de C.

    #include <stdio.h>
    #include <stdlib.h>
    #include <curl/curl.h>
    
    void upload_file(const char *signed_url, const char *file_path) {
        CURL *curl;
        CURLcode res;
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
        if (curl) {
            curl_easy_setopt(curl, CURLOPT_URL, signed_url);
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
            FILE *file = fopen(file_path, "rb");
            if (!file) {
                fprintf(stderr, "Failed to open file: %s\n", file_path);
                return;
            }
            fseek(file, 0, SEEK_END);
            long file_size = ftell(file);
            fseek(file, 0, SEEK_SET);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_size);
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            res = curl_easy_perform(curl);
            if (res != CURLE_OK)
                fprintf(stderr, "Upload failed: %s\n", curl_easy_strerror(res));
            else {
                long http_code = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
                printf("HTTP status code: %ld\n", http_code);
            }
            fclose(file);
            curl_easy_cleanup(curl);
        }
        curl_global_cleanup();
    }
    
    int main(int argc, char *argv[]) {
        if (argc != 3) {
            printf("Usage: %s <presigned URL> <file path>\n", argv[0]);
            return 1;
        }
        upload_file(argv[1], argv[2]);
        return 0;
    }
    

    Compile y ejecute el programa:

    gcc -o oss_upload oss_upload.c -lcurl
    ./oss_upload <presigned URL> <file path>
    

    El programa lee el tamaño del archivo local ubicado en file_path, lo envía como cuerpo de una solicitud PUT hacia signed_url mediante libcurl e imprime el código de estado HTTP devuelto (200 indica que la carga fue exitosa).

    Android

    import android.os.AsyncTask;
    import android.util.Log;
    
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class SignUrlUploadActivity extends AppCompatActivity {
    
        private static final String TAG = "SignUrlUploadActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Replace <signedUrl> with the presigned URL.
            String signedUrl = "<signedUrl>";
    
            // Specify the full path of the local file. By default, if you do not specify the full path, the local file is uploaded from the path of the project to which the sample program belongs.
            String pathName = "/storage/emulated/0/demo.txt";
    
            // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "text/plain;charset=utf8");
            headers.put("x-oss-storage-class", "Standard");
    
            // Specify user metadata. Make sure that the user metadata here is the same as the user metadata specified when the presigned URL was generated.
            Map<String, String> userMetadata = new HashMap<>();
            userMetadata.put("key1", "value1");
            userMetadata.put("key2", "value2");
    
            new UploadTask().execute(signedUrl, pathName, headers, userMetadata);
        }
    
        private class UploadTask extends AsyncTask<Object, Void, Integer> {
            @Override
            protected Integer doInBackground(Object... params) {
                String signedUrl = (String) params[0];
                String pathName = (String) params[1];
                Map<String, String> headers = (Map<String, String>) params[2];
                Map<String, String> userMetadata = (Map<String, String>) params[3];
    
                try {
                    URL url = new URL(signedUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("PUT");
                    connection.setDoOutput(true);
                    connection.setUseCaches(false);
    
                    // Specify request headers
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // Specify user metadata
                    for (Entry<String, String> meta : userMetadata.entrySet()) {
                        connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
                    }
    
                    // Read the local file
                    File file = new File(pathName);
                    FileInputStream fileInputStream = new FileInputStream(file);
                    DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
    
                    byte[] buffer = new byte[1024];
                    int count;
                    while ((count = fileInputStream.read(buffer)) != -1) {
                        dos.write(buffer, 0, count);
                    }
    
                    fileInputStream.close();
                    dos.flush();
                    dos.close();
    
                    // Obtain the response
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "Upload status code: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "The object is uploaded by using the network library");
                    } else {
                        Log.d(TAG, "Upload failed");
                    }
    
                    InputStream is = connection.getInputStream();
                    byte[] responseBuffer = new byte[1024];
                    StringBuilder responseStringBuilder = new StringBuilder();
                    while ((count = is.read(responseBuffer)) != -1) {
                        responseStringBuilder.append(new String(responseBuffer, 0, count));
                    }
                    Log.d(TAG, responseStringBuilder.toString());
    
                    return responseCode;
                } catch (IOException e) {
                    e.printStackTrace();
                    return -1;
                }
            }
    
            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
                if (result == 200) {
                    Toast.makeText(SignUrlUploadActivity.this, "Object uploaded", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Upload failed", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

Configurar la devolución de llamada de carga

Al cargar un objeto, puede incluir un parámetro de callback en la URL prefirmada para notificar automáticamente a su servidor de aplicaciones cuando finalice la carga. Para obtener más información sobre el funcionamiento de las devoluciones de llamada, consulte Callback.

  1. El propietario del objeto genera una URL prefirmada (con el método PUT) que contiene los parámetros de callback obligatorios para la carga.

    Python

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # Create a command-line argument parser and describe the script's purpose: to generate a presigned PUT request URL for an object (Presign Put Object).
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # Define command-line arguments, including the required region, bucket name, endpoint, and object key.
    parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
    parser.add_argument('--bucket', help='The name of the bucket.', required=True)
    parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
    parser.add_argument('--key', help='The name of the object.', required=True)
    
    def main():
        # Parse command-line arguments to get user-provided values.
        args = parser.parse_args()
    
        # Load access credential information from environment variables for identity verification.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # Create a configuration object using the SDK's default settings and set the authentication provider.
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # Set the region property of the configuration object based on the command-line arguments.
        cfg.region = args.region
    
        # If a custom endpoint is provided, update the endpoint property in the configuration object.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # Initialize the OSS client with the above configuration to interact with OSS.
        client = oss.Client(cfg)
    
        # Send a request to generate a presigned PUT request for the specified object.
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket,  # Bucket name
            key=args.key,  # Object key
            content_type='text/plain;charset=utf8',  # Specify the content type.
            storage_class='Standard',  # Specify the storage class.
            metadata={
                'key1': 'value1',   # Specify the metadata.
                'key2': 'value2'    # Specify the metadata.
            }
        ),expires=timedelta(seconds=3600)) # Set the expiration time in seconds. Here, it is set to 3600 seconds.
    
        # Print the method, expiration time, and URL of the presigned request to confirm the validity of the link.
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # Print the signed header information of the presigned request. This information will be included in the HTTP headers when the actual request is sent.
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # When this script is executed directly, call the main function to start the processing logic.
    if __name__ == "__main__":
        main()  # Script entry point. The program flow starts here.

    Go

    package main
    
    import (
    	"context"
    	"encoding/base64"
    	"encoding/json"
    	"flag"
    	"log"
    	"time"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // Define global variables.
    var (
    	region     string // The region in which the bucket is located.
    	bucketName string // The name of the bucket.
    	objectName string // The name of the object.
    )
    
    // Define the init function to initialize the command-line parameters.
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the object.")
    }
    
    func main() {
    	// Parse the command-line parameters.
    	flag.Parse()
    
    	// Check whether the bucket name is empty.
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, bucket name required")
    	}
    
    	// Check whether the region is empty.
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// Check whether the object name is empty.
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, object name required")
    	}
    
    	// Load the default configurations and specify the credential provider and region.
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// Create an OSS client.
    	client := oss.NewClient(cfg)
    
    	// Specify the callback parameters.
    	callbackMap := map[string]string{
    		"callbackUrl":      "http://example.com:23450",                                                                   // Specify the URL of the callback server, such as https://example.com:23450.
    		"callbackBody":     "bucket=${bucket}&object=${object}&size=${size}&my_var_1=${x:my_var1}&my_var_2=${x:my_var2}", // Specify the callback request body.
    		"callbackBodyType": "application/x-www-form-urlencoded",                                                          // Specify the Content-Type of the callback request body.
    	}
    
    	// Convert the callback parameter configurations into a JSON string, then Base64-encode it to pass the callback settings.
    	callbackStr, err := json.Marshal(callbackMap)
    	if err != nil {
    		log.Fatalf("failed to marshal callback map: %v", err)
    	}
    	callbackBase64 := base64.StdEncoding.EncodeToString(callbackStr)
    
    	callbackVarMap := map[string]string{}
    	callbackVarMap["x:my_var1"] = "thi is var 1"
    	callbackVarMap["x:my_var2"] = "thi is var 2"
    	callbackVarStr, err := json.Marshal(callbackVarMap)
    	if err != nil {
    		log.Fatalf("failed to marshal callback var: %v", err)
    	}
    	callbackVarBase64 := base64.StdEncoding.EncodeToString(callbackVarStr)
    
    	// Generate a presigned URL with the PutObject method.
    	result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{
    		Bucket:      oss.Ptr(bucketName),
    		Key:         oss.Ptr(objectName),
    		Callback:    oss.Ptr(callbackBase64),    // Specify the callback parameters, which are Base64-encoded JSON strings.
    		CallbackVar: oss.Ptr(callbackVarBase64), // Specify the custom callback parameters, which are Base64-encoded JSON strings.
    	},
    		oss.PresignExpires(10*time.Minute),
    	)
    	if err != nil {
    		log.Fatalf("failed to put object presign %v", err)
    	}
    
    	log.Printf("request method:%v\n", result.Method)
    	log.Printf("request expiration:%v\n", result.Expiration)
    	log.Printf("request url:%v\n", result.URL)
    	if len(result.SignedHeaders) > 0 {
    // When the response includes signature headers, you must set the corresponding request headers when sending a PUT request with the presigned URL.
    		log.Printf("signed headers:\n")
    		for k, v := range result.SignedHeaders {
    			log.Printf("%v: %v\n", k, v)
    		}
    	}
    }
    

    Java

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.CredentialsProviderFactory;
    import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
    import com.aliyun.oss.common.comm.SignVersion;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    
    import java.net.URL;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class OssPresignExample {
        public static void main(String[] args) throws Throwable {
            // This example uses the public endpoint of the China (Hangzhou) region. Specify the actual endpoint.
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Specify the bucket name, for example, examplebucket.
            String bucketName = "examplebucket";
            // Specify the full path of the object, for example, exampleobject.txt. The full path of the object cannot contain the bucket name.
            String objectName = "exampleobject.txt";
            // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the region to cn-hangzhou.
            String region = "cn-hangzhou";
    
            // Create an OSSClient instance.
            // When the OSSClient instance is no longer in use, call the shutdown method to release resources.
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            OSS ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
    
            URL signedUrl = null;
            try {
                // Construct the callback parameters.
                String callbackUrl = "http://www.example.com/callback";
                String callbackBody = "{\"callbackUrl\":\"" + callbackUrl + "\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}";
                String callbackBase64 = Base64.getEncoder().encodeToString(callbackBody.getBytes());
    
                String callbackVarJson = "{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}";
                String callbackVarBase64 = Base64.getEncoder().encodeToString(callbackVarJson.getBytes());
                // Set the request headers.
                Map<String, String> headers = new HashMap<String, String>();
                // Specify CALLBACK.
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK, callbackBase64);
                // Specify CALLBACK-VAR.
                headers.put(OSSHeaders.OSS_HEADER_CALLBACK_VAR, callbackVarBase64);
    
                // Set the expiration time (3600 seconds later).
                Date expiration = new Date(new Date().getTime() + 3600 * 1000);
    
                // Format the expiration time.
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                String expirationStr = dateFormat.format(expiration);
    
                // Construct the request.
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
                request.setMethod(HttpMethod.PUT);
                request.setExpiration(expiration);
                // Add the request headers to the request.
                request.setHeaders(headers);
    
                // Print the callback and callback-var parameters.
                System.out.println("callback:"+callbackBase64);
                System.out.println("callback-var:"+callbackVarBase64);
    
                // Generate the presigned URL.
                URL url = ossClient.generatePresignedUrl(request);
    
                // Print the result.
                System.out.println("method: PUT,");
                System.out.println(" expiration: " + expirationStr + ",");
                System.out.println(" url: " + url);
    
            } 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("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());
            }
        }
    }

    PHP

    <?php
    
    // Include the autoload file so that the required dependencies can be loaded.
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // Specify descriptions for command line arguments.
    $optsdesc = [
        "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located.
        "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // (Optional) Specify the endpoint that can be used by other services to access OSS.
        "bucket" => ['help' => 'The name of the bucket', 'required' => True], // (Required) Specify the name of the bucket.
        "key" => ['help' => 'The name of the object', 'required' => True], // (Required) Specify the name of the object.
    ];
    
    // Convert the descriptions to a list of long options required by getopt.
    // Add a colon (:) to the end of each parameter to indicate that a value is required.
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // Parse the command-line parameters.
    $options = getopt("", $longopts);
    
    // Check whether the required parameters are provided.
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // Get the help information for the parameter
            echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
            exit(1); // Exit the program if the required parameters are not configured.
        }
    }
    
    // Obtain values from the parsed parameters.
    $region = $options["region"]; // The region in which the bucket is located
    $bucket = $options["bucket"]; // The name of the bucket
    $key = $options["key"];       // The name of the object
    
    // Load access credentials from environment variables.
    // Use EnvironmentVariableCredentialsProvider to retrieve the AccessKey ID and AccessKey secret from environment variables.
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // Use the default configurations of the SDK.
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // Set the credentials provider
    $cfg->setRegion($region); // Set the region in which the bucket is located
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // Set the endpoint if provided
    }
    
    // Create an OSS client instance.
    $client = new Oss\Client($cfg);
    
    // Add x-oss-callback and x-oss-callback-var headers
    // Define the webhook address
    $call_back_url = "http://www.example.com/callback";
    
    // Construct callback parameters: specify the webhook address and request body, and use Base64 encoding
    // Use placeholders {var1} and {var2} to replace ${x:var1} and ${x:var2}
    $callback_body_template = "bucket={bucket}&object={object}&my_var_1={var1}&my_var_2={var2}";
    $callback_body_replaced = str_replace(
        ['{bucket}', '{object}', '{var1}', '{var2}'],
        [$bucket, $key, 'value1', 'value2'],
        $callback_body_template
    );
    $callback = base64_encode(json_encode([
        "callbackUrl" => $call_back_url,
        "callbackBody" => $callback_body_replaced
    ]));
    
    // Construct custom variables (callback-var) using Base64 encoding
    $callback_var = base64_encode(json_encode([
        "x:var1" => "value1",
        "x:var2" => "value2"
    ]));
    
    // Create a PutObjectRequest object to upload the object.
    // Note: contentType, metadata, and headers parameters are added here for signature calculation.
    $request = new Oss\Models\PutObjectRequest(
        bucket: $bucket,
        key: $key,
        callback:$callback,
        callbackVar:$callback_var,
    );
    
    // Call the presign method to generate a presigned URL.
    $result = $client->presign($request);
    
    // Print the presigned result, output the presigned URL that users can directly use to upload objects
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL .
        'put object url:' . $result->url . PHP_EOL
    );
    
  2. Otros usuarios cargan los objetos mediante la URL prefirmada con el método PUT.

    curl

    curl -X PUT -T /path/to/local/file "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"

    Java

    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.entity.FileEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.net.URL;
    import java.util.*;
    
    public class SignUrlUpload {
        public static void main(String[] args) throws Throwable {
            CloseableHttpClient httpClient = null;
            CloseableHttpResponse response = null;
    
            // Replace <signedUrl> with the authorized URL.
            URL signedUrl = new URL("<signedUrl>");
    
            // Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
            String pathName = "C:\\Users\\demo.txt";
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                httpClient = HttpClients.createDefault();
                response = httpClient.execute(put);
    
                System.out.println("Status code returned for the upload:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Upload successful using network library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                 if (response != null) {
                     response.close();
                 }
                 if (httpClient != null) {
                     httpClient.close();
                 }
             }
        }
    }       

    Go

    package main
    
    import (
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl, filePath string) error {
    	// Open the file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return fmt.Errorf("Unable to open file: %w", err)
    	}
    	defer file.Close()
    
    	// Create a new HTTP client.
    	client := &http.Client{}
    
    	// Create a PUT request.
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("Failed to create request: %w", err)
    	}
    
    	// Send the request.
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("Failed to send request: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// Read the response.
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("Failed to read response: %w", err)
    	}
    
    	fmt.Printf("Status code returned for the upload: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Upload successful using network library.")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace <signedUrl> with the authorized URL.
    	signedUrl := "<signedUrl>"
    
    	// Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
    	filePath := "C:\\Users\\demo.txt"
    
    	err := uploadFile(signedUrl, filePath)
    	if err != nil {
    		fmt.Println("An error occurred:", err)
    	}
    }
    

    python

    import requests
    
    def upload_file(signed_url, file_path):
        try:
            # Open the file.
            with open(file_path, 'rb') as file:
                # Send a PUT request to upload the file.
                response = requests.put(signed_url, data=file)
         
            print(f"Status code returned for the upload: {response.status_code}")
            if response.status_code == 200:
                print("Upload successful using network library.")
            print(response.text)
     
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # Replace <signedUrl> with the authorized URL.
        signed_url = "<signedUrl>"
        
        # Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
        file_path = "C:\\Users\\demo.txt"
    
        upload_file(signed_url, file_path)
    

    Node.js

    Importante

    Si se presenta un error 403 por discrepancia de firma al cargar un archivo con Node.js, generalmente se debe a que el encabezado de solicitud Content-Type se estableció de forma explícita en la carga. Sin embargo, dicho encabezado no se incluyó al generar la URL prefirmada. Esta discrepancia provoca un fallo en la verificación de la firma. Para resolver este problema, no configure el encabezado de solicitud Content-Type en la petición de carga o bien especifíquelo cuando genere la URL prefirmada.

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath) {
        try {
            // Create a read stream.
            const fileStream = fs.createReadStream(filePath);
    
            // Send a PUT request to upload the file.
            const response = await axios.put(signedUrl, fileStream);
    
            console.log(`Status code returned for the upload: ${response.status}`);
            if (response.status === 200) {
                console.log('Upload successful using network library.');
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // Main function.
    (async () => {
        // Replace <signedUrl> with the authorized URL.
        const signedUrl = '<signedUrl>';
        
        // Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    Importante

    Si se presenta un error 403 por discrepancia de firma al cargar un archivo con Browser.js, generalmente se debe a que el navegador añade automáticamente el encabezado de solicitud Content-Type. Este encabezado no se incluyó al generar la URL prefirmada, lo cual provoca un fallo en la verificación de la firma. Para resolver este problema, debe especificar el encabezado de solicitud Content-Type cuando genere la URL prefirmada.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>File Upload Example</title>
    </head>
    <body>
        <h1>File Upload Example</h1>
    
        <!-- Select a file -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // Replace this with the presigned URL generated in Step 1.
            const signedUrl = "<signedUrl>"; 
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (!file) {
                    alert('Please select a file to upload.');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('File uploaded successfully!');
                } catch (error) {
                    console.error('Error during upload:', error);
                    alert('Upload failed: ' + error.message);
                }
            });
    
            /**
             * Upload the file to OSS.
             * @param {File} file - The file to upload.
             * @param {string} presignedUrl - The presigned URL.
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,  // Upload the entire file directly.
                });
    
                if (!response.ok) {
                    throw new Error(`Upload failed, status: ${response.status}`);
                }
    
                console.log('File uploaded successfully');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
    var filePath = "C:\\Users\\demo.txt";
    // Replace <signedUrl> with the authorized URL.
    var presignedUrl = "<signedUrl>";
    
    // Create an HTTP client and open the local file stream.
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // Create a PUT request.
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // Send the request.
    var response = await httpClient.SendAsync(request);
    
    // Process the response.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Upload successful! Status code: {response.StatusCode}");
        Console.WriteLine("Response headers:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Upload failed! Status code: {response.StatusCode}");
        Console.WriteLine("Response content: " + responseContent);
    }

    C++

    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath) {
        CURL *curl;
        CURLcode res;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // Set the URL.
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // Set the request method to PUT.
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // Open the file.
            FILE *file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Unable to open file: " << filePath << std::endl;
                return;
            }
    
            // Get the file size.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);
    
            // Set the file size.
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Set the input file handle.
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
    
            // Execute the request.
            res = curl_easy_perform(curl);
    
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "Status code returned for the upload: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "Upload successful using network library." << std::endl;
                }
            }
    
            // Close the file.
            fclose(file);
    
            // Clean up.
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // Replace <signedUrl> with the authorized URL.
        std::string signedUrl = "<signedUrl>";
    
        // Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
        std::string filePath = "C:\\Users\\demo.txt";
    
        uploadFile(signedUrl, filePath);
    
        return 0;
    }
    

    Android

    package com.example.signurlupload;
    
    import android.os.AsyncTask;
    import android.util.Log;
    
    import java.io.DataOutputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class SignUrlUploadActivity {
    
        private static final String TAG = "SignUrlUploadActivity";
    
        public void uploadFile(String signedUrl, String filePath) {
            new UploadTask().execute(signedUrl, filePath);
        }
    
        private class UploadTask extends AsyncTask<String, Void, String> {
    
            @Override
            protected String doInBackground(String... params) {
                String signedUrl = params[0];
                String filePath = params[1];
    
                HttpURLConnection connection = null;
                DataOutputStream dos = null;
                FileInputStream fis = null;
    
                try {
                    URL url = new URL(signedUrl);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("PUT");
                    connection.setDoOutput(true);
                    connection.setRequestProperty("Content-Type", "application/octet-stream");
    
                    fis = new FileInputStream(filePath);
                    dos = new DataOutputStream(connection.getOutputStream());
    
                    byte[] buffer = new byte[1024];
                    int length;
    
                    while ((length = fis.read(buffer)) != -1) {
                        dos.write(buffer, 0, length);
                    }
    
                    dos.flush();
                    dos.close();
                    fis.close();
    
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "Status code returned for the upload: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "Upload successful using network library.");
                    }
    
                    return "Upload complete. Status code: " + responseCode;
    
                } catch (IOException e) {
                    e.printStackTrace();
                    return "Upload failed: " + e.getMessage();
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
    
            @Override
            protected void onPostExecute(String result) {
                Log.d(TAG, result);
            }
        }
    
        public static void main(String[] args) {
            SignUrlUploadActivity activity = new SignUrlUploadActivity();
            // Replace <signedUrl> with the authorized URL.
            String signedUrl = "<signedUrl>";
            // Specify the full path of the local file. If you do not specify a local path, the file is uploaded from the project path of the sample program by default.
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

Información adicional

¿Qué es una URL prefirmada?

Una URL prefirmada es un enlace seguro con límite de tiempo que otorga acceso temporal a un objeto específico en OSS. Para generarla, el cliente crea una firma criptográfica mediante el par de AccessKey, la ruta del recurso y el tiempo de expiración. Esta firma se añade a la URL original y produce un enlace de acceso temporal. El formato habitual de una URL prefirmada es https://BucketName.Endpoint/Object?Signature.

Cuando un tercero accede a la URL prefirmada, OSS valida la firma. Si la firma no es válida o ya expiró, se rechaza el acceso.

Ejemplo de URL prefirmada:

https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-process=image%2Fresize%2Cp_10&x-oss-date=20241115T095058Z&x-oss-expires=3600&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241115%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=6e7a********************************

Con este método, los propietarios de los objetos proporcionan acceso limitado a terceros de forma segura, sin revelar sus claves privadas.

Escenarios aplicables

  • Uso compartido temporal de objetos: para permitir que un tercero cargue o descargue un objeto específico de manera segura, el backend genera una URL prefirmada con límite de tiempo y la envía al frontend. El tercero utiliza esta URL para ejecutar la operación dentro del periodo permitido, lo que garantiza un acceso controlado y seguro a los datos.

  • Uso compartido flexible de objetos: los propietarios comparten sus objetos de forma segura al generar URL prefirmadas y distribuirlas a terceros por correo electrónico o aplicaciones de mensajería. Los destinatarios solo pegan la URL en su navegador para descargar los objetos deseados.

Preguntas frecuentes

¿Cómo puedo otorgar permisos más amplios a otros usuarios sobre mis recursos de OSS, en lugar de limitarlos únicamente a la carga?

Además de las URL prefirmadas, OSS ofrece un método de autorización temporal más flexible: las credenciales de acceso temporal de STS. A diferencia de las URL prefirmadas, que se limitan a acciones específicas, las credenciales de STS permiten que terceros ejecuten una mayor variedad de operaciones, como listar, copiar o eliminar objetos, con permisos sujetos a un límite de tiempo. Para obtener más información, consulte Access OSS by using STS temporary credentials.

¿Puedo restringir el acceso a mi objeto para que solo se permitan solicitudes desde sitios web específicos y se bloqueen todas las demás?

Sí, habilite la protección contra hotlinking basada en Referer mediante la configuración de una lista blanca que restrinja el acceso a sus recursos de OSS. De este modo, solo los sitios web autorizados (como el suyo) acceden a los recursos, y se bloquean las solicitudes directas de fuentes no autorizadas o malintencionadas. Para obtener más información, consulte Configure a Referer whitelist or blacklist to prevent other websites from linking to your OSS objects.

¿Por qué mi navegador muestra errores de CORS y cómo los soluciono?

Su bucket no tiene configurada ninguna política de intercambio de recursos de origen cruzado (CORS), o bien la configuración actual de CORS es incorrecta. Compruebe y ajuste los parámetros según las indicaciones de CORS.

¿Por qué mi navegador muestra el error "405 Method Not Allowed" y cómo lo soluciono?

El método de la solicitud es incorrecto. Cuando cargue un objeto mediante una URL prefirmada, asegúrese de utilizar el método PUT y no el método POST.

¿Por qué OSS almacena una cadena de URL en lugar del archivo real cuando paso una URL como cuerpo de la carga?

Al usar una URL prefirmada para cargar datos, este mecanismo funciona como un canal directo de carga entre el cliente y OSS. OSS almacena los bytes sin procesar del cuerpo de la solicitud PUT como el objeto; no interpreta el cuerpo como una URL ni recupera contenido de una dirección externa en su nombre.

Si pasa una cadena de URL (por ejemplo, https://example.com/video.mp4) como cuerpo de la solicitud PUT, OSS almacena esa cadena como el contenido del objeto. Por ejemplo, una cadena de URL de 66 bytes genera un objeto de 66 bytes que contiene únicamente el texto de la URL, no el archivo alojado en esa dirección.

Para almacenar en un bucket de OSS un archivo alojado en una URL externa, su servidor debe descargar primero los datos del archivo y luego cargar los bytes reales en OSS mediante PutObject o una carga multiparte. A continuación se muestra un ejemplo en Python que indica cómo implementar este reenvío desde el servidor:

import requests
import alibabacloud_oss_v2 as oss

def relay_url_to_oss(external_url, bucket_name, object_key, region):
    # Step 1: Download the file from the external URL.
    response = requests.get(external_url, stream=True)
    response.raise_for_status()
    file_content = response.content

    # Step 2: Configure the OSS client.
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = region
    client = oss.Client(cfg)

    # Step 3: Upload the downloaded data to OSS.
    result = client.put_object(oss.PutObjectRequest(
        bucket=bucket_name,
        key=object_key,
        body=file_content,
    ))
    print(f"Upload successful. ETag: {result.etag}")

# Example usage
relay_url_to_oss(
    external_url="https://example.com/sample.jpg",
    bucket_name="examplebucket",
    object_key="sample.jpg",
    region="cn-hangzhou"
)