All Products
Search
Document Center

Object Storage Service:Upload files using signed URLs (Go SDK V2)

Last Updated:Sep 02, 2026

By default, objects in an Object Storage Service (OSS) bucket are private and can be accessed only by the object owner. This topic describes how to use the OSS Go software development kit (SDK) V2 to generate a signed URL for the PUT method with a time-to-live (TTL). This allows other users to temporarily upload objects. The URL can be used multiple times before it expires. After the URL expires, you must generate a new one.

Precautions

  • The sample code in this topic uses the cn-hangzhou region ID and a public Endpoint for the China (Hangzhou) region. If you want to access OSS from other Alibaba Cloud products in the same region, use an internal network Endpoint. For more information about the mappings between OSS regions and Endpoints, see Regions and Endpoints.

  • The examples in this topic show how to obtain access credentials from environment variables. For more information about how to configure access credentials, see Configure access credentials.

  • Permissions are not required to generate a presigned URL. However, a third party can successfully upload a file using the presigned URL only if the user who generates the URL has the oss:PutObject permission. For more information about how to grant permissions, see Grant custom permissions to a RAM user.

  • The sample code in this topic uses a V4 signed URL, which has a maximum TTL of 7 days. For more information, see Signature V4 (recommended).

Process

The following figure shows the process of uploading a file using a presigned URL for a PUT request.

image

Method definition

You can call the presign operation to generate a signed URL. This operation grants temporary access to an object in a bucket. The signed URL can be used multiple times before it expires.

The presign operation is defined as follows:

func (c *Client) Presign(ctx context.Context, request any, optFns ...func(*PresignOptions)) (result *PresignResult, err error)

Request parameters

Parameter

Type

Description

ctx

context.Context

The context of the request.

request

*PutObjectRequest

The name of the operation for which to generate the signed URL.

optFns

...func(*PresignOptions)

(Optional) The TTL. If you do not specify this parameter, the default TTL is 15 minutes.

The PresignOptions are listed below:

Option

Type

Description

Expires

time.Duration

The duration from the current time until the URL expires. For example, to set a TTL of 30 minutes, use 30 * time.Minute.

Expiration

time.Time

The absolute expiration time.

Important

For V4 signatures, the maximum TTL is 7 days. If you set both Expiration and Expires, Expiration takes precedence.

Return values

Return value

Type

Description

result

*PresignResult

The result. It includes the signed URL, HTTP method, expiration time, and signed request headers.

err

error

The status of the request. If the request fails, err is not nil.

The PresignResult return values are listed below:

Parameter

Type

Description

Method

string

The HTTP method that corresponds to the operation. For example, for the PutObject operation, PUT is returned.

URL

string

Pre-signed URL

Expiration

time.Time

The expiration time of the signed URL.

SignedHeaders

map[string]string

The signed request headers. For example, if you set Content-Type for the PutObject operation, information about Content-Type is returned.

Sample code

  1. The object owner generates a signed URL for the PUT method.

    Important

    When you generate a signed URL for the PUT method, if you specify request headers, you must include the same headers when you use the signed URL to send the PUT request. If the headers do not match, the request fails and a signature error is returned.

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

    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 with specified request headers and custom metadata using a signed URL

  1. The object owner generates a signed URL for the PUT method.

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

    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 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";
    
            // Set the request headers. The request header information must be the same as the information used when the 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 ContentType.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // Set the custom user metadata. The custom user metadata must be the same as the information used when the 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 set header parameters, such as user metadata and storage class, when you generate the presigned URL, you must also send these parameters to the server when you use the presigned URL to upload the file. A signature error is reported if the parameters sent to the server are inconsistent with the signed parameters.
                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. When you use other methods to generate a presigned URL for an upload, you must also add the 'x-oss-meta-' prefix to the userMeta.
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                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 (
    	"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 a 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 custom user metadata.
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// Send the request.
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// Process the response.
    	fmt.Printf("Status code returned for the upload: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Upload successful using network library.")
    	} else {
    		fmt.Println("Upload failed.")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	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"
    
    	// Set the request headers. The request header information must be the same as the information used when the URL was generated.
    	headers := map[string]string{
    		"Content-Type": "text/plain;charset=utf8",
    		"x-oss-storage-class": "Standard",
    	}
    
    	// Set the custom user metadata. The custom user metadata must be the same as the information used when the 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 a file to OSS.
    
        :param signed_url: The presigned 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"Status code returned for the upload: {response.status_code}")
                if response.status_code == 200:
                    print("Upload successful using 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 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 directory where the script is located by default.
        file_path = "C:\\Users\\demo.txt"
    
        // Set the request headers. The request header information must be the same as the information used when the URL was generated.
        headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        }
    
        // Set the custom user metadata. The custom user metadata must be the same as the information used when the 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 {
            // 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 a PUT request.
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`Status code returned for the upload: ${response.status}`);
            if (response.status === 200) {
                console.log("Upload successful using 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 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 directory where the script is located by default.
        const filePath = "C:\\Users\\demo.txt";
    
        // Set the request headers. The request header information must be the same as the information used when the URL was generated.
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // Set the custom user metadata. The custom user metadata must be the same as the information used when the URL was generated.
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    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 (Java SDK)</h1>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // Replace this 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. 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;
    
    // If you set header parameters, such as user metadata and storage class, when you generate the presigned URL, you must also send these parameters to the server when you use the presigned URL to upload the file. A signature error is reported if the parameters sent to the server are inconsistent with the signed parameters.
    // Set the request headers. The request header information must be the same as the information used when the URL was generated.
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "utf8" };  // Specify the ContentType.       
    // Set the custom user metadata. The custom user metadata must be the same as the information used when the 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");
    
    // Print the request headers.
    Console.WriteLine("Request headers:");
    foreach (var header in request.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    
    // 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>
    #include <map>
    #include <string>
    
    // Callback function to handle 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 << "Unable 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 handling 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 << "Status code returned for the upload: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "Upload successful using 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 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";
    
        // Set the request headers. The request header information must be the same as the information used when the URL was generated.
        std::map<std::string, std::string> headers = {
             {"Content-Type", "text/plain;charset=utf8"},
             {"x-oss-storage-class", "Standard"}
        };
    
        // Set the custom user metadata. The custom user metadata must be the same as the information used when the 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 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 pathName = "/storage/emulated/0/demo.txt";
    
            // Set the request headers. The request header information must be the same as the information used when the URL was generated.
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "text/plain;charset=utf8");
            headers.put("x-oss-storage-class", "Standard");
    
            // Set the custom user metadata. The custom user metadata must be the same as the information used when the 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);
    
                    // Set the request headers.
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // Set the custom user 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, "Status code returned for the upload: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "Upload successful using 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();
                }
            }
        }
    }
    

Troubleshooting: HTTP 403 SignatureDoesNotMatch caused by a Content-Type mismatch

If you specify a Content-Type when you generate the signed URL, but the upload request does not include a Content-Type header or includes a different value, OSS returns HTTP 403 SignatureDoesNotMatch. The Content-Type header in the upload request must exactly match the Content-Type used when the signed URL was generated.

You can resolve this issue in either of the following ways:

  • Add the same Content-Type header to the upload request as the one used when you generated the signed URL.

  • Do not specify Content-Type when you generate the signed URL, and do not include a Content-Type header in the upload request.

Note

Misconfigured CORS settings can cause cross-origin upload failures in a browser, but CORS issues are not related to the HTTP 403 SignatureDoesNotMatch error. If you encounter this error, check Content-Type consistency first before investigating CORS configuration.

Perform a multipart upload using a signed URL

To perform a multipart upload using a signed URL, you must configure the part size and generate a signed URL for each part. The following sample code provides an example:

package main

import (
	"bytes"
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

var (
	region     string                     // The region.
	bucketName string                     // The bucket name.
	objectName string                     // The object name.
	length     = int64(5000 * 1024)       // The total file size in bytes.
	partSize   = int64(200 * 1024)        // The size of each part in bytes.
	partsNum   = int(length/partSize + 1) // The number of parts.
	data       = make([]byte, length)     // The simulated data for the upload.
)

// Initialize command-line parameters.
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the object.")
}

func main() {
	// Parse command-line parameters.
	flag.Parse()

	// Check if the required parameters are set.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, bucket name required")
	}

	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, object name required")
	}

	// Configure the OSS client.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Create an OSS client.
	client := oss.NewClient(cfg)

	// Initialize the multipart upload.
	initResult, err := client.InitiateMultipartUpload(context.TODO(), &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	})
	if err != nil {
		log.Fatalf("failed InitiateMultipartUpload %v", err)
	}

	// Traverse each part, generate a signed URL, and upload the part.
	for i := 0; i < partsNum; i++ {
		start := int64(i) * partSize
		end := start + partSize
		if end > length {
			end = length
		}
		signedResult, err := client.Presign(context.TODO(), &oss.UploadPartRequest{
			Bucket:     oss.Ptr(bucketName),
			Key:        oss.Ptr(objectName),
			PartNumber: int32(i + 1),
			Body:       bytes.NewReader(data[start:end]),
			UploadId:   initResult.UploadId,
		}, oss.PresignExpiration(time.Now().Add(1*time.Hour))) // Generate a signed URL with a TTL of 1 hour.
		if err != nil {
			log.Fatalf("failed to generate presigned URL %v", err)
		}
		fmt.Printf("signed url:%#v\n", signedResult.URL) // Print the generated signed URL.

		// Create an HTTP request and upload the part.
		req, err := http.NewRequest(signedResult.Method, signedResult.URL, bytes.NewReader(data[start:end]))
		if err != nil {
			log.Fatalf("failed to create HTTP request %v", err)
		}

		c := &http.Client{} // Create an HTTP client.
		_, err = c.Do(req)
		if err != nil {
			log.Fatalf("failed to upload part by signed URL %v", err)
		}
	}

	// List the uploaded parts.
	partsResult, err := client.ListParts(context.TODO(), &oss.ListPartsRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		UploadId: initResult.UploadId,
	})
	if err != nil {
		log.Fatalf("failed to list parts %v", err)
	}

	// Collect information about the uploaded parts.
	var parts []oss.UploadPart
	for _, p := range partsResult.Parts {
		parts = append(parts, oss.UploadPart{PartNumber: p.PartNumber, ETag: p.ETag})
	}

	// Complete the multipart upload.
	result, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		UploadId: initResult.UploadId,
		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
			Parts: parts,
		},
	})
	if err != nil {
		log.Fatalf("failed to complete multipart upload %v", err)
	}

	// Print the result of the completed multipart upload.
	log.Printf("complete multipart upload result:%#v\n", result)
}

Upload a file and set upload callback parameters using a signed URL

  1. The object owner generates a signed URL for the PUT method with specified upload callback parameters.

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

    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):
        """
        Upload a file to OSS using a presigned URL.
    
        :param signed_url: The presigned URL.
        :param file_path: The full path of the file to upload.
        :param headers: Optional. Custom HTTP headers.
        :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"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 authorized URL.
        signed_url = "<signedUrl>"
    
        # Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the directory where the script is located by default.
        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 file 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
        }
    
        // Set 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("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, _ := io.ReadAll(resp.Body)
        fmt.Println(string(body))
    
        return nil
    }
    
    func main() {
        // Replace <signedUrl> with the authorized URL.
        signedUrl := "<signedUrl>"
        // Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the project's corresponding local path by default.
        filePath := "C:\\Users\\demo.txt"
    
        // Set request headers. The header information here must be consistent with the information used to generate the URL.
        headers := map[string]string{
            "x-oss-callback":     "eyJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9XHUwMDI2b2JqZWN0PSR7b2JqZWN0fVx1MDAyNnNpemU9JHtzaXplfVx1MDAyNm15X3Zhcl8xPSR7eDpteV92YXIxfVx1MDAyNm15X3Zhcl8yPSR7eDpteV92YXIyfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCJjYWxsYmFja1VybCI6Imh0dHA6Ly9leGFtcGxlLmNvbToyMzQ1MCJ9",
            "x-oss-callback-var": "eyJ4Om15X3ZhcjEiOiJ0aGkgaXMgdmFyIDEiLCJ4Om15X3ZhcjIiOiJ0aGkgaXMgdmFyIDIifQ==",
        }
    
        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 IOException {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
    
        // Replace <signedUrl> with the authorized URL.
        URL signedUrl = new URL("<signedUrl>");
    
        // Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the project's corresponding local path by default.
        String pathName = "C:\\Users\\demo.txt";
    
        // Set 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 header parameters were set when generating the presigned URL, these parameters must also be sent to the server when using the presigned URL to upload the file. If the signature and the parameters sent to the server do not match, a signature error will occur.
          for(Map.Entry<String, String> header: headers.entrySet()){
            put.addHeader(header.getKey(),header.getValue());
          }
    
          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 {
          if (response != null) {
            response.close();
          }
          if (httpClient != null) {
            httpClient.close();
          }
        }
      }
    }       

    PHP

    <?php
    
    function uploadFile($signedUrl, $filePath, $headers = []) {
        // Check if the file exists.
        if (!file_exists($filePath)) {
            echo "File does not exist: $filePath\n";
            return;
        }
    
        // Initialize 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));
    
        // Execute cURL request.
        $response = curl_exec($ch);
    
        // Get HTTP status code.
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // Close cURL session.
        curl_close($ch);
    
        // Output the result.
        echo "Upload status code returned: $httpCode\n";
        if ($httpCode == 200) {
            echo "Upload successful using the network library.\n";
        } else {
            echo "Upload failed.\n";
        }
        echo $response . "\n";
    }
    
    // Replace <signedUrl> with the authorized URL.
    $signedUrl = "<signedUrl>";
    
    // Enter the full path of the local file. If you do not specify a local path, the file is uploaded from the directory where the script is located by default.
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

References

  • For the complete sample code for signed URLs, see GitHub example.

  • For more information about the API operation for signed URLs, see Presign.