Por padrão, a lista de controle de acesso (ACL) de um objeto em um bucket do Object Storage Service (OSS) é privada. Assim, apenas o proprietário tem permissão para acessá-lo. No entanto, ele pode gerar uma URL pré-assinada para conceder acesso temporário a terceiros, permitindo o upload de objetos dentro de um período especificado. Esse recurso viabiliza cenários como o envio de contratos por parceiros ou a submissão de imagens de perfil por usuários.
Observações de uso
Este tópico utiliza o endpoint público da região China (Hangzhou). Para acessar o OSS a partir de outros serviços da Alibaba Cloud na mesma região, use um endpoint interno. Para obter detalhes sobre as regiões e endpoints suportados, consulte Regions and endpoints.
A geração de uma URL pré-assinada não exige permissões. Contudo, um terceiro só conseguirá fazer upload de um arquivo com sucesso usando a URL pré-assinada se você possuir a permissão
oss:PutObject. Para mais informações, consulte Grant a custom access policy to a RAM user.URLs pré-assinadas não suportam uploads via FormData. Para uploads com FormData, utilize form uploads.
Fluxo de trabalho
A figura a seguir ilustra o processo de upload de um objeto para o OSS usando uma URL pré-assinada.
Usar uma URL pré-assinada para fazer upload de um objeto
-
O proprietário do bucket gera uma URL pré-assinada que permite requisições PUT.
NotaUma URL pré-assinada gerada com o SDK do OSS tem validade máxima de 7 dias. Se você gerar a URL usando um token do Security Token Service (STS), a validade pode chegar a 12 horas (43.200 segundos).
Java
Para obter informações sobre como usar o OSS SDK for Java para gerar uma URL pré-assinada, 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 saber como usar o OSS SDK for Go na geração de uma URL pré-assinada, 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(®ion, "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
Consulte OSS SDK for Python para detalhes sobre a geração de URLs pré-assinadas com o 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
O exemplo abaixo gera uma URL pré-assinada para uploads comuns. Para aprender a gerar URLs com parâmetros de processamento de imagem ou ID de versão usando o OSS SDK for Node.js, acesse 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
Este exemplo demonstra a geração de uma URL pré-assinada para uploads padrão. Caso precise incluir um ID de versão, consulte a documentação do OSS SDK for PHP em 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
Consulte Authorize access (Android SDK) para instruções sobre como gerar URLs pré-assinadas com o OSS SDK for Android.
// 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 informações sobre a geração de URLs pré-assinadas usando o OSS SDK for C++, 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
Consulte Authorize access (iOS SDK) para aprender a gerar URLs pré-assinadas com o OSS SDK for iOS.
// 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 detalhes sobre como usar o OSS SDK for .NET na criação de URLs pré-assinadas, 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
Acesse Authorize access (C SDK) para mais informações sobre a geração de URLs pré-assinadas por meio do OSS SDK for C.
#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; }
-
Terceiros fazem o upload dos objetos enviando uma requisição PUT por meio da URL pré-assinada.
ImportanteÉ possível usar uma URL pré-assinada várias vezes antes que ela expire. Entretanto, ao fazer upload do mesmo objeto repetidamente, cada novo envio sobrescreve o anterior. Após a expiração da URL, o proprietário precisa gerar uma nova URL pré-assinada (conforme mostrado em Step 1) para garantir acesso contínuo aos terceiros.
Usar URLs pré-assinadas para fazer upload de objetos em partes
Caso precise enviar objetos grandes e enfrente dificuldades ou impossibilidade de integrar um SDK do OSS ao seu cliente, considere realizar uploads multipart usando URLs pré-assinadas. Nessa abordagem, o servidor inicia o processo de upload e atribui uma URL pré-assinada a cada parte, permitindo que seu cliente ou service de terceiros faça o envio individualmente. Depois que todas as partes forem carregadas com sucesso, o servidor as combina em um objeto completo.
O upload de objetos em partes via URLs pré-assinadas é mais complexo do que usar um SDK do OSS. Ao adotar essa estratégia, certifique-se de que seu cliente envie a parte correspondente ao número especificado na URL pré-assinada. A ausência de uma parte ou a incompatibilidade entre elas causa falha na combinação final. Se o seu cliente suportar a integração com o SDK do OSS, recomendamos o uso de client direct uploads baseado em tokens STS para maior simplicidade e estabilidade.
|
|
|
-
O cliente envia uma requisição de upload multipart.
Envie uma requisição de upload multipart incluindo o nome do objeto, o tamanho do objeto e o tamanho da parte. O tamanho máximo permitido para cada parte é de 5 GB, mas recomenda-se usar 5 MB.
O código abaixo exemplifica uma requisição de upload multipart enviada pelo cliente. Ao usar o exemplo, lembre-se de substituir
https://yourserver.com/init-uploadpelo endpoint de inicialização real em seu servidor.curl -X POST https://yourserver.com/init-upload \ -H "Content-Type: application/json" \ -d '{ "fileName": "exampleobject.jpg", "fileSize": 104857600, "partSize": 5242880 }' -
O servidor inicia o upload multipart e gera as URLs pré-assinadas.
Chame a operação InitiateMultipartUpload para iniciar o upload e obter o upload ID.
Calcule o número de partes com base no tamanho do objeto e no tamanho definido para cada parte.
Gere uma URL pré-assinada específica para cada parte.
Retorne a lista de URLs pré-assinadas no formato JSON.
NotaO servidor registra o upload ID, que identifica exclusivamente o upload multipart e serve para verificar e combinar as partes posteriormente. Armazene esse ID usando cache, bancos de dados ou outros métodos adequados.
-
O cliente faz o upload do objeto em partes.
Envie requisições PUT para carregar as partes individuais usando as URLs pré-assinadas retornadas pelo servidor. Cada parte deve ser enviada seguindo o mesmo procedimento descrito em uploading an object with a presigned URL. Após concluir o upload de todas as partes, notifique o servidor para que ele realize a combinação.
NotaUploads multipart via URLs pré-assinadas permitem processamento concorrente, mas é fundamental garantir que cada URL seja usada exclusivamente para sua parte designada. Por exemplo, a parte número N na URL deve ser usada estritamente para enviar a enésima parte do arquivo; não é permitido reutilizar ou pular números de partes.
O comando de exemplo a seguir envia a primeira parte (/path/to/local/file representa o caminho do arquivo 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" -
(Opcional) O servidor verifica as partes enviadas.
Opcionalmente, configure o servidor para validar as partes carregadas assim que receber a notificação de conclusão do upload.
Verifique a integridade das partes recebidas.
Confirme se cada parte possui o tamanho esperado.
NotaA verificação das partes requer o upload ID registrado anteriormente.
-
O servidor combina as partes e retorna o resultado do upload.
Após a aprovação na verificação das partes, o servidor invoca a operação CompleteMultipartUpload para unir tudo em um único objeto e devolve o resultado do upload ao cliente.
Configure cabeçalhos para definir a política de upload
Ao gerar uma URL pré-assinada, defina uma política de upload especificando o parâmetro Header. É possível configurar cabeçalhos como x-oss-storage-class (para definir a classe de armazenamento) e Content-Type (para especificar o tipo do objeto).
Se você incluir cabeçalhos durante a geração da URL pré-assinada, será obrigatório fornecer os mesmos cabeçalhos no momento do upload do objeto. Caso haja divergência, o OSS retornará um erro 403 devido à falha na verificação da assinatura.
Para consultar a lista de cabeçalhos suportados, consulte PutObject. Também é possível configurar cabeçalhos personalizados para gerenciar metadados do objeto. Para mais detalhes, acesse Manage object metadata.
-
O proprietário do objeto gera uma URL pré-assinada contendo o 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(®ion, "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. -
Terceiros fazem o upload dos objetos usando a URL pré-assinada e fornecendo os mesmos cabeçalhos.
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
ImportanteAo usar código Browser.js para fazer upload de um objeto com base em uma URL pré-assinada, você pode encontrar um erro 403 indicando inconsistência de assinatura. Esse erro ocorre devido a uma falha na verificação da assinatura, pois o navegador adiciona automaticamente o cabeçalho de requisição Content-Type, elemento que não foi especificado durante a geração da URL pré-assinada. Para resolver o problema, especifique o cabeçalho Content-Type ao gerar uma URL pré-assinada destinada a ser usada em códigos Browser.js para envio de dados ao 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
Diferentemente do exemplo em C++, que depende de
std::stringe<iostream>/<fstream>e, portanto, exige um compilador C++, o exemplo a seguir foi escrito em C padrão (usandochar*,<stdio.h>e libcurl) para que possa ser compilado e executado com uma toolchain C simples.#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 e execute:
gcc -o oss_upload oss_upload.c -lcurl ./oss_upload <presigned URL> <file path>O programa lê o tamanho do arquivo local em
file_path, envia-o como corpo de uma requisição PUT parasigned_urlusando libcurl e imprime o código de status HTTP retornado (200 indica que o upload foi bem-sucedido).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(); } } } }
Configure callback de upload
Durante o upload de um objeto, inclua um parâmetro de callback na URL pré-assinada para notificar automaticamente o servidor da aplicação assim que o envio for concluído. Para entender melhor o funcionamento dos callbacks, consulte Callback.
-
O proprietário do objeto gera uma URL pré-assinada (com o método PUT) contendo os parâmetros necessários para o callback de upload.
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(®ion, "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 ); -
Outros usuários fazem o upload dos objetos usando a URL pré-assinada com o 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
ImportanteSe você encontrar um erro 403 de incompatibilidade de assinatura ao usar Node.js para enviar um arquivo, geralmente isso ocorre porque o cabeçalho de requisição Content-Type foi definido explicitamente na requisição de upload, mas não foi incluído quando a URL pré-assinada foi gerada. Essa discrepância causa falha na verificação da assinatura. Para resolver o problema, não defina o cabeçalho Content-Type na requisição de upload ou especifique-o ao gerar a URL pré-assinada.
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
ImportanteCaso enfrente um erro 403 de incompatibilidade de assinatura ao usar Browser.js para upload de arquivos, a causa provável é a adição automática do cabeçalho Content-Type pelo navegador, o qual não estava presente na geração da URL pré-assinada. Tal diferença provoca falha na validação da assinatura. Para corrigir, é imprescindível especificar o cabeçalho Content-Type no momento da criação da URL pré-assinada.
<!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); } }
Informações adicionais
O que é uma URL pré-assinada?
Uma URL pré-assinada é um link seguro e com tempo limitado que concede acesso temporário a um objeto específico no OSS. Para gerá-la, o cliente cria uma assinatura criptográfica usando o par de AccessKey, o caminho do recurso e o tempo de expiração. Essa assinatura é anexada à URL original, produzindo um link de acesso temporário. O formato típico de uma URL pré-assinada é https://BucketName.Endpoint/Object?Signature.
Quando um terceiro acessa a URL pré-assinada, o OSS valida a assinatura. Se a assinatura for inválida ou estiver expirada, o acesso será negado.
Exemplo de URL pré-assinada:
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********************************
Com esse método, os proprietários de objetos podem fornecer acesso limitado a terceiros de forma segura, sem jamais revelar suas chaves privadas.
Cenários aplicáveis
Compartilhamento temporário de objetos: Para permitir que um terceiro faça upload ou download seguro de um objeto específico, o backend gera uma URL pré-assinada com tempo limitado e a fornece ao frontend. O terceiro pode então usar essa URL para executar a operação dentro do prazo permitido, garantindo acesso controlado e seguro aos dados.
Compartilhamento flexível de objetos: Os proprietários podem compartilhar seus objetos com segurança gerando URLs pré-assinadas e distribuindo-as por e-mail ou aplicativos de mensagens para terceiros. Os destinatários simplesmente colam as URLs em seus navegadores para baixar os objetos desejados.