All Products
Search
Document Center

Object Storage Service:Upload a file using a signed URL (Harmony SDK)

Last Updated:Dec 16, 2025

By default, files in an Object Storage Service (OSS) bucket are private, and only the file owner has permission to upload them. You can use the OSS Harmony software development kit (SDK) to generate a signed URL that grants upload permission to other users. When you generate a signed URL, you can set an expiration time to limit its validity. The signed URL can be used multiple times before it expires. If multiple upload operations are performed using the same URL, the file may be overwritten. After the URL expires, it becomes invalid for uploads, and you must generate a new one.

Precautions

  • For information about the regions and endpoints supported by OSS, see Access OSS through bucket domain names.

  • When you generate a signed URL for a PUT request, you must have the oss:PutObject permission. For more information, see Grant custom access policies to RAM users.

    Note

    When you generate a signed URL, the SDK calculates a signature on the client using your local access credentials and appends the signature to the URL. This process does not require a network request to the server. Therefore, the caller does not need special permissions to generate the URL. However, the entity that generates the URL must have the required permissions for the operation. This ensures that users who receive the signed URL can access the authorized resource.

  • The sample code in this topic uses V4 signed URLs, which are valid for a maximum of 7 days. For more information, see Signature V4 (Recommended).

Procedure

The procedure for uploading a file using a signed URL with the PUT method is as follows:

image

Sample code

  1. The file owner generates a signed URL for a PUT request.

    Important

    When you generate a signed URL for a PUT request, if you specify request headers, you must include the same headers in the PUT request that uses the signed URL. If the headers do not match, the request fails with a signature error.

    import Client, {  EHttpMethod } from '@aliyun/oss';
    
    // Create an OSS client instance.
    const client = new Client({
      // Replace with the AccessKeyId of your STS temporary access credential.
      accessKeyId: 'yourAccessKeyId',
      // Replace with the AccessKeySecret of your STS temporary access credential.
      accessKeySecret: 'yourAccessKeySecret',
      // Replace with the SecurityToken of your STS temporary access credential.
      securityToken: 'yourSecurityToken',
      // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set Region to oss-cn-hangzhou.
      region: 'oss-cn-hangzhou',
    });
    
    // Specify the name of the bucket to operate on. Replace with your actual bucket name.
    const bucket = 'yourBucketName';
    // Specify the name of the object (file) for which to generate the signed URL. Replace with your actual object name.
    const key = 'yourObjectName';
    
    /**
     * Generates a signed URL for uploading an object.
     * Uses the signatureUrl method to generate a signed URL for a PUT request.
     */
    const signatureUrlForPutObject = async () => {
      /**
       * If no signature version is explicitly declared, the version specified in Client.options.signVersion is used by default.
       */
      const url = await client.signatureUrl({
        method: EHttpMethod.PUT, // The request method is PUT.
        bucket,                  // The bucket name.
        key,                     // The object (file) name.
        expires: 60 * 60,       // Set the expiration time to 60 minutes (in seconds).
      });
    
      // Print the generated signed URL.
      console.log(url);
    };
    
    signatureUrlForPutObject();
  2. Another user uploads the file using the signed URL for the PUT request.

    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 {
                response.close();
                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

    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, {
                headers: {
                    'Content-Type': 'application/octet-stream' // Adjust the Content-Type as needed.
                }
            });
    
            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

    Important

    If you encounter a 403 signature mismatch error when you use Browser.js to upload a file, it is usually because the browser automatically adds the Content-Type request header, but this header was not specified when the presigned URL was generated. This causes a signature verification failure. To resolve this issue, you must specify the Content-Type request header when you generate the 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 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);
        }
    }
    

Common scenarios

Upload a file by specifying request headers in a signed URL

  1. The file owner generates a signed URL for a PUT request that specifies the Content-Type request header.

    import Client, { EHeaderKey, EHttpMethod } from '@aliyun/oss';
    
    // Create an OSS client instance.
    const client = new Client({
      // Replace with the AccessKeyId of your STS temporary access credential.
      accessKeyId: 'yourAccessKeyId',
      // Replace with the AccessKeySecret of your STS temporary access credential.
      accessKeySecret: 'yourAccessKeySecret',
      // Replace with the SecurityToken of your STS temporary access credential.
      securityToken: 'yourSecurityToken',
      // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set Region to oss-cn-hangzhou.
      region: 'oss-cn-hangzhou',
    });
    
    // Specify the name of the bucket to operate on. Replace with your actual bucket name.
    const bucket = 'yourBucketName';
    // Specify the name of the object (file) for which to generate the signed URL. Replace with your actual object name.
    const key = 'yourObjectName';
    
    
    /**
     * Generates a signed URL for uploading an object.
     * Uses the signatureUrl method to generate a signed URL for a PUT request and specifies the Content-Type header.
     */
    const signatureUrlForPutObject = async () => {
      /**
       * If no signature version is explicitly declared, the version specified in Client.options.signVersion is used by default.
       */
      const url = await client.signatureUrl({
        method: EHttpMethod.PUT, // The request method is PUT.
        bucket,                  // The bucket name.
        key,                     // The object (file) name.
        expires: 60 * 60,       // Set the expiration time to 60 minutes (in seconds).
        headers: {
          [EHeaderKey.CONTENT_TYPE]: 'text/plain;charset=utf-8', // Set the Content-Type header.
        },
      });
    
      // Print the generated signed URL.
      console.log(url);
    };
    
    signatureUrlForPutObject();
  2. Another user uploads the file using the signed URL for the PUT request.

    curl -X PUT \
         -H "Content-Type: text/plain;charset=utf-8" \
         -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******************************************************"
    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 signed URL.
            URL signedUrl = new URL("<signedUrl>");
    
            // Specify the full path of the local file. If no local path is specified, the file is uploaded from the corresponding local path of the project where the sample program resides.
            String pathName = "C:\\Users\\demo.txt";
    
            // Set the request headers. The header information must be the same as the information used to generate the URL.
            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 ContentType.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/
    
            // Set the user-defined metadata. The metadata must be the same as the information used to generate the URL.
            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 header parameters, such as user-defined metadata and storage class, are set when the signed URL is generated, these parameters must also be sent to the server when you use the signed URL to upload the file. If the signature does not match the parameters sent to the server, 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 you use userMeta, the SDK internally adds the "x-oss-meta-" prefix to userMeta. When you use other methods to generate a signed URL for an upload, you must also add the "x-oss-meta-" prefix to userMeta.
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Upload status code returned: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Upload successful using the network library");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       
    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        Upload a file to OSS using a signed URL.
    
        :param signed_url: The signed URL.
        :param file_path: The full path of the file to upload.
        :param headers: Optional. Custom HTTP headers.
        :param metadata: Optional. Custom metadata.
        :return: None
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # Update headers and add the metadata prefix.
        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"Upload status code returned: {response.status_code}")
                if response.status_code == 200:
                    print("Upload successful 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 <signedUrl> with the signed URL.
        signed_url = "<signedUrl>"
       
        # Specify the full path of the local file. If no local path is specified, the file is uploaded from the directory where the script resides.
        file_path = "C:\\Users\\demo.txt"
    
        # Set the request headers. The header information must be the same as the information used to generate the URL.
        headers = {
             "Content-Type": "text/plain; charset=utf8",
             "x-oss-storage-class": "Standard"
        }
    
        # Set the user-defined metadata. The metadata must be the same as the information used to generate the URL.
        metadata = {
             "key1": "value1",
             "key2": "value2"
        }
    
        upload_file(signed_url, file_path, headers, metadata)
    
    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // Update headers and add 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 the PUT request.
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`Upload status code returned: ${response.status}`);
            if (response.status === 200) {
                console.log("Upload successful using the network library");
            } else {
                console.log("Upload failed");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // Main function.
    (async () => {
        // Replace <signedUrl> with the signed URL.
        const signedUrl = "<signedUrl>";
    
        // Specify the full path of the local file. If no local path is specified, the file is uploaded from the directory where the script resides.
        const filePath = "C:\\Users\\demo.txt";
    
        // Set the request headers. The header information must be the same as the information used to generate the URL.
        const headers = {
            // "Content-Type": "text/txt",
            // "x-oss-storage-class": "Standard"
        };
    
        // Set the user-defined metadata. The metadata must be the same as the information used to generate the URL.
        const metadata = {
            // "key1": "value1",
            // "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    
    <!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 (Harmony SDK)</h1>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // Replace this with the actual signed URL.
            const signedUrl = "<signedUrl>"; 
    
            // Set Content-Type, storageClass, and metadata.
            const contentType = 'text/plain';
    
            const storageClass = 'Standard';
    
            const metadata = {
                'x-oss-meta-key1': 'value1',
                'x-oss-meta-key2': 'value2'
            };
    
            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 {
                    console.error('Please select a file');
                    alert('Please select a file to upload.');
                }
            });
    
            const upload = async (file, presignedUrl) => {
                const chunkSize = 1024 * 1024;
                let start = 0;
                let end = chunkSize;
    
                while (start < file.size) {
                    const chunk = file.slice(start, end);
                    
                    const headers = {
                        'Content-Type': contentType,
                        'x-oss-storage-class':storageClass,
                        ...metadata
                    };
                    
                    const response = await fetch(presignedUrl, {
                        method: 'PUT',
                        headers: headers,
                        body: chunk
                    });
    
                    if (!response.ok) {
                        throw new Error(`Upload failed for chunk, status: ${response.status}`);
                    }
    
                    console.log('Chunk uploaded successfully'); 
                    start = end;
                    end = start + chunkSize;
                }
    
                console.log('File uploaded successfully'); 
            };
        </script>
    </body>
    </html>
    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    #include <map>
    #include <string>
    
    // Callback function 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) {
            // 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 << "Failed to open file: " << filePath << std::endl;
                return;
            }
    
            // Set the file size.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // Set the file read callback.
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Set the 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);
    
            // Set the response processing callback.
            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 returned: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "Upload successful 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 signed URL.
        std::string signedUrl = "<signedUrl>";
    
        // Specify the full path of the local file. If no local path is specified, the file is uploaded from the corresponding local path of the project where the sample program resides.
        std::string filePath = "C:\\Users\\demo.txt";
    
        // Set the request headers. The header information must be the same as the information used to generate the URL.
        std::map<std::string, std::string> headers = {
            // {"Content-Type", "text/txt"},
            // {"x-oss-storage-class", "Standard"}
        };
    
        // Set the user-defined metadata. The metadata must be the same as the information used to generate the URL.
        std::map<std::string, std::string> metadata = {
            // {"key1", "value1"},
            // {"key2", "value2"}
        };
    
        uploadFile(signedUrl, filePath, headers, metadata);
    
        return 0;
    }
    
    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 file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Read the file content.
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// Create the request.
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// Set the request headers.
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// Set the user-defined 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("Upload status code returned: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Upload successful using the network library")
    	} else {
    		fmt.Println("Upload failed")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Replace <signedUrl> with the signed URL.
    	signedUrl := "<signedUrl>"
    
    	// Specify the full path of the local file. If no local path is specified, the file is uploaded from the corresponding local path of the project where the sample program resides.
    	filePath := "C:\\Users\\demo.txt"
    
    	// Set the request headers. The header information must be the same as the information used to generate the URL.
    	headers := map[string]string{
    		// "Content-Type": "text/txt",
    		// "x-oss-storage-class": "Standard",
    	}
    
    	// Set the user-defined metadata. The metadata must be the same as the information used to generate the URL.
    	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)
    	}
    }
    
    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 signed URL.
            String signedUrl = "<signedUrl>";
    
            // Specify the full path of the local file. If no local path is specified, the file is uploaded from the corresponding local path of the project where the sample program resides.
            String pathName = "/storage/emulated/0/demo.txt";
    
            // Set the request headers. The header information must be the same as the information used to generate the URL.
            Map<String, String> headers = new HashMap<>();
            // headers.put("Content-Type", "text/txt");
            // headers.put("x-oss-storage-class", "Standard");
    
            // Set the user-defined metadata. The metadata must be the same as the information used to generate the URL.
            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);
    
                    // Set the request headers.
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // Set the user-defined metadata.
                    for (Entry<String, String> meta : userMetadata.entrySet()) {
                        connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
                    }
    
                    // Read the 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();
    
                    // Get the response.
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "Upload status code returned: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "Upload successful 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, "Upload successful", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Upload failed", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }