All Products
Search
Document Center

:Use a presigned URL to upload an object

Last Updated:Jul 01, 2025

By default, the access control list (ACL) of an Object Storage Service (OSS) object in a bucket is private. Only the object owner has the permissions to upload an object to the bucket. You can use OSS SDK for Python to generate a presigned URL and share the presigned URL with a user to allow the user to upload an object. When you generate a presigned URL, you can specify the validity period of the presigned URL to limit the period of time during which the user can upload an object. During the validity period of the presigned URL, the user can use the URL to upload an object to the bucket multiple times. If you upload an object multiple times, the uploaded object may be overwritten. After the validity period of the presigned URL ends, the user cannot use the presigned URL to upload an object. In this case, you must generate a new presigned URL.

Usage notes

  • The sample code in this topic uses the region ID cn-hangzhou of the China (Hangzhou) region. By default, a public endpoint is used to access resources in a bucket. If you want to access resources in the bucket by using other Alibaba Cloud services in the same region in which the bucket is located, use an internal endpoint. For more information about OSS regions and endpoints, see Regions and endpoints.

  • You do not need specific permissions to generate a presigned URL. However, to allow others to use the presigned URL for uploading an object, you must have the oss:PutObject permission. For more information, see Authorize a RAM user to access multiple directories in a bucket.

  • In this topic, presigned URLs that include V4 signatures and have a validity period of up to seven days are used. For more information, see (Recommended) Include a V4 signature in a URL.

Process

The following figure shows how to use a presigned URL that allows HTTP PUT requests to upload an object to OSS.

image

Method

You can call a specific operation to generate a presigned URL and use the presigned URL to grant temporary access permissions on objects in a bucket. You can use the signed URL multiple times before the URL expires.

Syntax:

presign(request: PutObjectRequest, **kwargs) → PresignResult

Request parameters

Parameter

Type

Description

request

PutObjectRequest

The API operation used to generate a presigned URL. For more information, see Client.presign.

expires

datetime.timedelta

The validity period of the presigned URL. This is an optional parameter. For example, if you want to set the validity period to 30 minutes, set expires to 30 * time.Minute. If you do not specify this parameter, the presigned URL uses the default value, which is 15 minutes.

expiration

datetime.datetime

The absolute expiration time of the presigned URL. This is an optional parameter.

Important

If you use the V4 signature algorithm, the validity period can be up to seven days. If you specify both Expiration and Expires, Expiration takes precedence.

Response parameters

Type

Description

PresignResult

The returned results, including the presigned URL, HTTP method, expiration time, and request headers specified in the request. For more information, see PresignResult.

Response parameters of PresignResult

Parameter

Type

Description

method

str

The HTTP method, which corresponds to the API operation. For example, the HTTP method of the PutObject operation is PUT.

url

str

The presigned URL.

expiration

datetime

The expiration time of the presigned URL.

signed_headers

MutableMapping

The signed headers specified in the request. For example, if Content-Type is specified, information about Content-Type is returned.

For the more information about the presign method, visit presign.

Sample code

  1. Generate a presigned URL that allows HTTP PUT requests.

    Important

    If you specify request headers when you generate a presigned URL that allows HTTP PUT requests, make sure that the request headers are included in the PUT request initiated by using the presigned URL. This prevents request failures and signature errors.

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # Create a command line parameter parser and describe the purpose of the script. The example describes how to generate a presigned URL that allows HTTP PUT requests.
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # Specify the command line parameters, including the required region, bucket name, endpoint, and object name.
    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 the command line parameters to obtain the values specified by the user.
        args = parser.parse_args()
    
        # Obtain access credentials from environment variables for authentication.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # Use the default configurations of the SDK to create a configuration object and specify the credential provider.
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # Specify the region attribute of the configuration object based on the command line parameters specified by the user.
        cfg.region = args.region
    
        # If a custom endpoint is provided, modify the endpoint parameter in the configuration object.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # Use the preceding configurations to initialize the OSSClient instance and allow the instance to interact with OSS.
        client = oss.Client(cfg)
    
        # Send the request to initiate a PUT request and generate a presigned URL for the specified object.
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket, # The name of the bucket.
            key=args.key, # The name of the object.
        ),expires=timedelta(seconds=3600)) # Specify the validity period of the request. In this example, the validity period is set to 3,600 seconds.
    
        # Display the method, expiration time, and presigned URL specified in the request to check the validity of the presigned URL.
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # Display the signed headers in the request, which are included in the HTTP header when the request is sent.
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # Call the main function to start the processing logic when the script is directly run.
    if __name__ == "__main__":
        main() # Specify the entry points in the functions of the script. The control program flow starts here.
  2. Use the presigned URL that allows HTTP PUT requests to upload an object.

    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 presigned URL. 
            URL signedUrl = new URL("<signedUrl>");
    
            // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
            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:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    Go

    package main
    
    import (
    	"fmt"
    	"io"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl, filePath string) error {
    	// Open the local file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return fmt.Errorf("Unable to open the local file: %w", err)
    	}
    	defer file.Close()
    
    	// Create an 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 the request: %w", err)
    	}
    
    	// Send the request.
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("Failed to send the 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 the request: %w", err)
    	}
    
    	fmt.Printf("Status code: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("The object is uploaded by using the library.")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace <signedUrl> with the presigned URL. 
    	signedUrl := "<signedUrl>"
    
    	// Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
    	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 local file that you want to upload.
            with open(file_path, 'rb') as file:
                # Send a PUT request to upload the local file.
                response = requests.put(signed_url, data=file)
         
            print(f"Status code: {response.status_code}")
            if response.status_code == 200:
                print("The object is uploaded by using the library.")
            print(response.text)
     
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # Replace <signedUrl> with the generated signed URL. 
        signed_url = "<signedUrl>"
        
        # Specify the full path of the local file. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
        file_path = "C:\\Users\\demo.txt"
    
        upload_file(signed_url, file_path)
    

    Node.js

    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 local file.
            const response = await axios.put(signedUrl, fileStream, {
                headers: {
                    'Content-Type': 'application/octet-stream' // Specify the Content-Type parameter.
                }
            });
    
            console.log(`Status code: ${response.status}`);
            if (response.status === 200) {
                console.log("The object is uploaded by using the library.");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // Specify the main function.
    (async () => {
        // Replace <signedUrl> with the presigned URL. 
        const signedUrl = '<signedUrl>';
        
        // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    Important

    When uploading an object using Browser.js and a presigned URL, a 403 SignatureNotMatch error that indicates signature inconsistency may occur. This is typically caused by the browser's automatic inclusion of the Content-Type request header, which that was not specified when the presigned URL was generated. To prevent this error, ensure that the Content-Type header is specified when generating a presigned URL.

    <!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 File -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // Replace <signedUrl> with the presigned URL that was 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 a file to OSS.
             * @param {File} file - The file to be uploaded.
             * @param {string} presignedUrl - The presigned URL.
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,  // Upload the entire file.
                });
    
                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 that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
    var filePath = "C:\\Users\\demo.txt";
    // Replace <signedUrl> with the presigned URL.
    var presignedUrl = "<signedUrl>";
    
    // Create an HTTP client and a 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 a request.
    var response = await httpClient.SendAsync(request);
    
    // Process the response.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}");
        Console.WriteLine("Response Header:");
        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) {
            // Specify the presigned 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 file: " << filePath << std::endl;
                return;
            }
    
            // Query the size of the local file.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);
    
            // Specify the size of the local file.
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Specify 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: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "The object is uploaded by using the network library." << std::endl;
                }
            }
    
            // Close the local file.
            fclose(file);
    
            // Clear the cURL handle.
            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 that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
        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: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "The object is uploaded by using the library.");
                    }
    
                    return "Object uploaded. 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 presigned URL. 
            String signedUrl = "<signedUrl>";
            // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

Common scenarios

Use a presigned URL that contains specific request headers and user metadata to upload an object

  1. Generate a presigned URL that contains specific request headers and user metadata and allows HTTP PUT requests.

    import argparse
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # Create a command line parameter parser and describe the purpose of the script. The example describes how to generate a presigned URL that allows HTTP PUT requests.
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # Specify the command line parameters, including the required region, bucket name, endpoint, and object name.
    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 the command line parameters to obtain the values specified by the user.
        args = parser.parse_args()
    
        # Obtain access credentials from environment variables for authentication.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # Use the default configurations of the SDK to create a configuration object and specify the credential provider.
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # Specify the region attribute of the configuration object based on the command line parameters specified by the user.
        cfg.region = args.region
    
        # If a custom endpoint is provided, modify the endpoint parameter in the configuration object.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # Use the preceding configurations to initialize the OSSClient instance and allow the instance to interact with OSS.
        client = oss.Client(cfg)
    
        # Send the request to initiate a PUT request and generate a presigned URL for the specified object.
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket, # The name of the bucket.
            key=args.key, # The name of the object.
            content_type='text/plain;charset=utf8', # Specify the type of the object.
            storage_class='Standard', # Specify the storage class of the object.
            metadata={
                'key1': 'value1', # Specify the metadata of the object.
                'key2': 'value2' # Specify the metadata of the object.
            }
        ),expires=timedelta(seconds=3600)) # Specify the validity period of the request. In this example, the validity period is set to 3,600 seconds.
    
    
        # Display the method, expiration time, and presigned URL specified in the request to check the validity of the presigned URL.
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # Display the signed headers in the request, which are included in the HTTP header when the request is sent.
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # Call the main function to start the processing logic when the script is directly run.
    if __name__ == "__main__":
        main() # Specify the entry points in the functions of the script. The control program flow starts here.
  2. Use the presigned URL that allows HTTP PUT requests to upload an object.

    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 <signedUrl> with the presigned URL. 
            URL signedUrl = new URL("<signedUrl>");
    
            // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, 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 those specified when the presigned URL was generated. 
            Map<String, String> headers = new HashMap<String, String>();
            // Specify the storage class of the object. 
            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 here is the same as the user metadata specified when the presigned URL was generated. 
            Map<String, String> userMetadata = new HashMap<String, String>();
            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 different from the headers 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 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 a 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 library.")
    	} else {
    		fmt.Println("Upload failed")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace <signedUrl> with the presigned URL. 
    	signedUrl := "<signedUrl>"
    
    	// Specify the full path of the local file that you want to upload. If the path of the local file is not specified, 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 here is the same as the user metadata specified when the presigned URL was generated. 
    	metadata := map[string]string{
    		"key1": "value1",
    		"key2": "value2",
    	}
    
    	err := uploadFile(signedUrl, filePath, 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 presigned 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: request headers. This parameter is optional. 
        :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 library.")
                else:
                    print("Upload failed.")
                print(response.text)
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # Replace <signedUrl> with the generated signed URL. 
        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 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 specified when the pesigned URL was 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 {
            // Add the x-oss-meta- prefix to the metadata keys.
            for (const [key, value] of Object.entries(metadata)) {
                headers[`x-oss-meta-${key}`] = value;
            }
    
            // Create a readable 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 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 <signedUrl> with the presigned URL. 
        const signedUrl = "<signedUrl>";
    
        // Specify the full path of the local file that you want to upload. By default, if you do not specify the full path of the 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 here is the same as the user metadata specified when the presigned URL was generated. 
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    Important

    When you use Browser.js code to upload an object based on a presigned URL, you may encounter a 403 error that indicates a signature inconsistency. This error arises from a signature verification failure, which occurs because the browser automatically adds the Content-Type request header, an element that was not specified when the presigned URL was generated. To resolve the error, you must specify the Content-Type header when you generate a presigned URL that is expected to be used in Browser.js code to upload data to OSS.

    <!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>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // Replace <signedUrl> with the actual presigned URL.
            const signedUrl = "<signedUrl>"; 
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (file) {
                    try {
                        await upload(file, signedUrl);
                    } catch (error) {
                        console.error('Error during upload:', error);
                        alert('Upload failed: ' + error.message);
                    }
                } else {
                    alert('Please select a file to upload.');
                }
            });
    
            const upload = async (file, presignedUrl) => {
                const headers = {
                    "Content-Type": "text/plain;charset=utf8",
                    'x-oss-storage-class': 'Standard',
                    'x-oss-meta-key1': 'value1',
                    'x-oss-meta-key2': 'value2'
                };
    
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    headers: headers,
                    body: file
                });
    
                if (!response.ok) {
                    throw new Error(`Upload failed, status: ${response.status}`);
                }
    
                alert('File uploaded successfully');
                console.log('File uploaded successfully');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. 
    var filePath = "C:\\Users\\demo.txt";
    // Replace <signedUrl> with the presigned URL.
    var presignedUrl = "<signedUrl>";
    
    // Create an HTTP client and a 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;
    
    // 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.
    // Specify request headers. Make sure that the values of the request headers are the same as those specified when the presigned URL was generated.
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "utf8" };  // 指定ContentType       
    // Specify user metadata. Make sure that the user metadata is the same as the user metadata specified when the pesigned URL was generated.
    request.Content.Headers.Add("x-oss-meta-key1", "value1");
    request.Content.Headers.Add("x-oss-meta-key2", "value2");
    // Specify the storage class of the object.
    request.Content.Headers.Add("x-oss-storage-class", "Standard");
    
    // Output the request header.
    Console.WriteLine("Request header:");
    foreach (var header in request.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    
    // Send a request.
    var response = await httpClient.SendAsync(request);
    
    // Process the response.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}");
        Console.WriteLine("Response Header:");
        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>
    #include <map>
    #include <string>
    
    // Specify the 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 presigned 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 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 << "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;
            }
    
            // Clear the cURL handle.
            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 that you want to upload. If the path of the local file is not specified, 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;
    }
    

    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 that you want to upload. If the path of the local file is not specified, 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, "Status code: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "The object is uploaded by using the 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();
                }
            }
        }
    }
    

Use a presigned URL to upload an object by using multipart upload

To use presigned URLs to upload an object by using multipart upload, you must configure the part size and generate a presigned URL for each part. Sample code:

import argparse
import os
import requests
import alibabacloud_oss_v2 as oss

# Create a command-line parameter parser and describe the purpose of the script. The example describes how to generate presigned URLs to upload an object by using multipart upload.
parser = argparse.ArgumentParser(description="presign multipart upload sample")

# Specify the --region parameter, which specifies the region in which the bucket is located. This command line parameter is required.
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
# Specify the --bucket parameter, which specifies the region in which the bucket is located. This command line parameter is required.
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
# Specify the --endpoint parameter, which specifies the endpoint that other services can use to access OSS. This command line parameter is optional.
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
# Specify the --key parameter, which specifies the name of the object. This command line parameter is required.
parser.add_argument('--key', help='The name of the object.', required=True)
# Specify the --file_path parameter, which specifies the path in which you want to store the object. This command line parameter is required.
parser.add_argument('--file_path', help='The path of Upload file.', required=True)

def main():
    # Parse the command line parameters to obtain the values entered by the user.
    args = parser.parse_args()

    # Load the authentication information required to access OSS from the environment variables.
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

    # Use the default configurations of the SDK to create a configuration object and specify the credential provider.
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider

    # Specify the region attribute of the configuration object based on the command line parameters specified by the user.
    cfg.region = args.region

    # If a custom endpoint is provided, modify the endpoint parameter in the configuration object.
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    # Use the preceding configurations to initialize the OSSClient instance and allow the instance to interact with OSS.
    client = oss.Client(cfg)

    # Set the part size to 1 MB.
    part_size = 1024 * 1024
    # Obtain the size of the local file.
    data_size = os.path.getsize(args.file_path)
    part_number = 1
    upload_parts = []

    # Initiate a multipart upload request.
    init_pre_result = client.presign(oss.InitiateMultipartUploadRequest(
        bucket=args.bucket,
        key=args.key,
    ))

    # Send the multipart upload request.
    with requests.post(init_pre_result.url, headers=init_pre_result.signed_headers) as resp:
        obj = oss.InitiateMultipartUploadResult()
        oss.serde.deserialize_xml(xml_data=resp.content, obj=obj)

        # Open the local file and read the content.
        with open(args.file_path, 'rb') as f:
            for start in range(0, data_size, part_size):
                n = part_size
                if start + n > data_size:
                    n = data_size - start
                reader = oss.io_utils.SectionReader(oss.io_utils.ReadAtReader(f), start, n)

                # Initiate a request to generate a presigned URL for a part.
                up_pre_result = client.presign(oss.UploadPartRequest(
                    bucket=args.bucket,
                    key=args.key,
                    upload_id=obj.upload_id,
                    part_number=part_number,
                ))

                # Split the local file into parts.
                with requests.put(up_pre_result.url, headers=up_pre_result.signed_headers, data=reader) as up_result:
                    print(f'status code: {up_result.status_code},'
                          f' request id: {up_result.headers.get("x-oss-request-id")},'
                          f' part number: {part_number},'
                          f' hash crc64: {up_result.headers.get("x-oss-hash-crc64ecma")},'
                          f' content md5: {up_result.headers.get("Content-MD5")},'
                          f' etag: {up_result.headers.get("ETag")},'
                          f' server time: {up_result.headers.get("x-oss-server-time")}'
                    )

                    # Record the ETag and the number of each part.
                    upload_parts.append(oss.UploadPart(part_number=part_number, etag=up_result.headers.get("ETag")))
                part_number += 1

        # Sort the parts by part number.
        parts = sorted(upload_parts, key=lambda p: p.part_number)

        # Complete the multipart upload request.
        request = oss.CompleteMultipartUploadRequest(
            bucket=args.bucket,
            key=args.key,
            upload_id=obj.upload_id,
            complete_multipart_upload=oss.CompleteMultipartUpload(
                parts=parts
            )
        )

        # Serialize the parameters.
        op_input = oss.serde.serialize_input(request, oss.OperationInput(
            op_name='CompleteMultipartUpload',
            method='POST',
            bucket=request.bucket,
        ))

        # Generate a request to upload the local file by using multipart upload.
        complete_pre_result = client.presign(request)

        # Complete the multipart upload request.
        with requests.post(complete_pre_result.url, headers=complete_pre_result.signed_headers, data=op_input.body) as complete_resp:
            result = oss.CompleteMultipartUploadResult()
            oss.serde.deserialize_xml(xml_data=complete_resp.content, obj=result)
            print(f'status code: {complete_resp.status_code},'
                  f' request id: {complete_resp.headers.get("x-oss-request-id")},'
                  f' hash crc64: {complete_resp.headers.get("x-oss-hash-crc64ecma")},'
                  f' content md5: {complete_resp.headers.get("Content-MD5")},'
                  f' etag: {complete_resp.headers.get("ETag")},'
                  f' content length: {complete_resp.headers.get("content-length")},'
                  f' content type: {complete_resp.headers.get("Content-Type")},'
                  f' url: {result.location},'
                  f' encoding type: {result.encoding_type},'
                  f' server time: {complete_resp.headers.get("x-oss-server-time")}'
            )

        # Display the method, expiration time, and presigned URL returned for the request.
        print(f'method: {complete_pre_result.method},'
              f' expiration: {complete_pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {complete_pre_result.url}'
        )

        # Display the signed headers in the request.
        for key, value in complete_pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')

# Call the main function to start the processing logic when the script is directly run.
if __name__ == "__main__":
    main() # Specify the entry points in the functions of the script. The control program flow starts here.

Use a presigned URL to upload an object and set upload callback parameters

  1. Generate a presigned URL that includes upload callback parameters to enable uploads using HTTP PUT requests.

    import argparse
    import base64
    import requests
    import alibabacloud_oss_v2 as oss
    
    from datetime import datetime, timedelta
    
    # Create a command line parameter parser and describe the purpose of the script. The example describes how to generate a presigned URL that allows HTTP PUT requests.
    parser = argparse.ArgumentParser(description="presign put object sample")
    
    # Specify the command line parameters, including the required region, bucket name, endpoint, and object name.
    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 the command-line parameters.
        args = parser.parse_args()
    
        # Obtain access credentials from environment variables for authentication.
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    
        # Use the default configuration to create a cfg object and specify the credential provider.
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # Set the region attribute of the cfg object to the region provided in the command line.
        cfg.region = args.region
    
        # If a custom endpoint is provided, update the endpoint attribute of the cfg object with the provided endpoint.
        if args.endpoint is not None:
            cfg.endpoint = args.endpoint
    
        # Use the preceding configuration to initialize the OSSClient instance.
        client = oss.Client(cfg)
    
        # Specify a custom callback URL.
        call_back_url = "http://www.example.com/callback"
        # Construct the callback parameter: specify the callback URL and request body, and encode the parameters in Base64.
        callback=base64.b64encode(str('{\"callbackUrl\":\"' + call_back_url + '\",\"callbackBody\":\"bucket=${bucket}&object=${object}&my_var_1=${x:var1}&my_var_2=${x:var2}\"}').encode()).decode()
        # Define and Base64-encode custom callback variables.
        callback_var=base64.b64encode('{\"x:var1\":\"value1\",\"x:var2\":\"value2\"}'.encode()).decode()
    
        # Send the request to initiate a PUT request and generate a presigned URL for the specified object.
        pre_result = client.presign(oss.PutObjectRequest(
            bucket=args.bucket,  # Name of the bucket.
            key=args.key,  # Name of the object.
            callback=callback,
            callback_var=callback_var,
        ),expires=timedelta(seconds=3600)) # Specify the validity period of the request. In this example, the validity period is set to 3,600 seconds.
    
        # Display the method, expiration time, and presigned URL specified in the request to check the validity of the presigned URL.
        print(f'method: {pre_result.method},'
              f' expiration: {pre_result.expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z")},'
              f' url: {pre_result.url}'
              )
    
        # Display the signed headers in the request, which are included in the HTTP header when the request is sent.
        for key, value in pre_result.signed_headers.items():
            print(f'signed headers key: {key}, signed headers value: {value}')
    
    # Call the main function to start the processing logic when the script is directly run.
    if __name__ == "__main__":
        main()  # Specify the entry point of the script. The control flow starts here.
  2. Use the presigned URL to upload an object.

    curl

    curl -X PUT \
         -H "x-oss-callback: eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9" \
         -H "x-oss-callback-var: eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==" \
         -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******************************************************"

    Python

    import requests
    
    def upload_file(signed_url, file_path, headers=None):
        """
        Use a presigned URL to upload an object to OSS.
    
        :param signed_url: Presigned URL.
        :param file_path: Full path of the local file to be uploaded.
        :param headers: Request headers. This parameter is optional.
        :return: None
        """
        if not headers:
            headers = {}
    
        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 library.")
                else:
                    print("Upload failed.")
                print(response.text)
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # Replace <signedUrl> with the presigned URL.
        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 directory in which the script is stored.
        file_path = "C:\\Users\\demo.txt"
    
        headers = {
            "x-oss-callback": "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
            "x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
        }
    
        upload_file(signed_url,  file_path, headers)

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io"
    
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string) error {
    	// Open the file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Read the content.
    	fileBytes, err := io.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.Add(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 library.")
    	} else {
    		fmt.Println("Upload failed.")
    	}
    	body, _ := io.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace <signedUrl> with the presigned URL.
    	signedUrl := "<signedUrl>"
    	// Specify the full path of the local file. If the path of the local file is not specified, 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{
    		"x-oss-callback":     "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
    		"x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers)
    	if err != nil {
    		fmt.Printf("An error occurred: %v\n", err)
    	}
    }
    

    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 presigned URL.
            URL signedUrl = new URL("<signedUrl>");
    
            // Specify the full path of the local file. If the path of the local file is not specified, 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, including x-oss-callback and x-oss-callback-var.
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("x-oss-callback", "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9");
            headers.put("x-oss-callback-var", "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==");
    
            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 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 different from the headers 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());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Status code: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("The object is uploaded by using the library.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    PHP

    <?php
    
    function uploadFile($signedUrl, $filePath, $headers = []) {
        // Check whether the file exists.
        if (!file_exists($filePath)) {
            echo "The file does not exist: $filePath\n";
            return;
        }
    
        // Initialize a cURL session.
        $ch = curl_init();
    
        // Set cURL options.
        curl_setopt($ch, CURLOPT_URL, $signedUrl);
        curl_setopt($ch, CURLOPT_PUT, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_INFILE, fopen($filePath, 'rb'));
        curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function($key, $value) {
            return "$key: $value";
        }, array_keys($headers), $headers));
    
        // Perform the cURL request.
        $response = curl_exec($ch);
    
        // Query the HTTP status code.
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // Close the cURL session.
        curl_close($ch);
    
        // Output the result
        echo "Status code: $httpCode\n";
        if ($httpCode == 200) {
            echo "The object is uploaded by using the library.\n";
        } else {
            echo "Upload failed.\n";
        }
        echo $response . "\n";
    }
    
    // Replace <signedUrl> with the presigned URL.
    $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 directory in which the script is stored.
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

FAQ

When I use a signed URL to upload a local file, is the file uploaded if the signed URL expires during the upload?

Yes, the file is uploaded even if the signed URL expires during the upload.

A presigned URL is used during the upload. The URL can be used within its validity period. The validity period of the URL is the minimum value of the validity period of the token and the presigned validity period.

If I do not specify request headers and user metadata when I generate a URL, do I need to specify request headers and user metadata when I use the URL to upload a local file?

You do not need to specify request headers and user metadata.

The request headers and user metadata are optional parameters. If you do not specify request headers and user metadata, delete the relevant code in the preceding example.

References