How to upload files to OSS from a WeChat mini program

Updated at:

You can upload files such as images, documents, and videos from a WeChat mini program to Object Storage Service (OSS) for cloud storage and distribution.

Solution overview

The following describes the process of uploading a file from a WeChat mini program to OSS:

image

To upload files from a WeChat mini program to OSS, you can follow these two steps:

  1. Configure the server side: On the server side, you create an ECS instance to obtain temporary access credentials from Security Token Service (STS). You then use these credentials to generate a signature that the WeChat mini program can use to upload files to OSS.

  2. Configure the WeChat mini program: On the mini program platform, you configure the bucket domain name as a valid domain name for the WeChat mini program. This ensures that WeChat does not block requests from the mini program to OSS. On the WeChat mini program client, you implement the logic to obtain the signature from the ECS instance and use it to upload files to OSS.

Procedure

Step 1: Configure the server side

Note

In a real-world deployment, if you already have an ECS server, you do not need to create a new ECS instance. You can proceed directly to Calculate the signature on the ECS server side.

  1. Create and connect to an ECS instance.

    Procedure

    Create an ECS instance

    Go to the Custom Launch page and create an ECS instance by selecting the required basic resources as described in the following sections.

    1. Select a region and billing method

      1. Select a billing method based on your business needs. This topic uses the pay-as-you-go billing method as an example. This method is flexible.

      2. Select a region based on your latency requirements. The closer the physical distance to the ECS instance, the lower the network latency and the faster the access speed. This topic uses the China (Hangzhou) region as an example.

    1. Create a VPC and a vSwitch

      When you create a VPC, select the same region as the ECS instance and configure the CIDR block as required. This topic uses the creation of a VPC and vSwitch in the China (Hangzhou) region as an example. After the VPC and vSwitch are created, return to the ECS purchase page, refresh the page, and then select the VPC and vSwitch.

      Note

      You can create a vSwitch when you create a VPC.

    1. Select an instance type and image

      Select an instance type and an image. The selected image determines the operating system and its version. In this topic, the instance type is set to ecs.e-c1m1.large, which is cost-effective and meets the testing requirements. The image is the public image Alibaba Cloud Linux 3.2104 LTS 64-bit.

    1. Select storage

      Select a system disk for the ECS instance and a data disk if needed. For the simple web system in this topic, you only need a system disk to store the operating system. A data disk is not required.

    1. Assign a public IP address

      This instance must be accessible from the public network. To simplify the process, this topic shows how to directly assign a public IP address to the instance. You can also associate an EIP with the instance after it is created. For more information, see Associate an EIP with a cloud resource.

      Note
      • If you do not assign a public IP address, you cannot use SSH or RDP to directly access the instance over the public network. You also cannot verify the web service deployment on the instance over the public network.

      • This topic uses the Pay-by-traffic bandwidth billing method. In this method, you are charged based on the amount of data transferred over the Internet. For more information, see Public bandwidth billing.

    1. Create a security group

      Create a security group for the instance. A security group is a virtual firewall that controls inbound and outbound traffic for ECS instances. When you create the security group, you must allow traffic on the following ports to access the ECS instance.

      Port range: SSH (22), RDP (3389), HTTP (80), and HTTPS (443).

      Note

      The security group created here has a default rule that sets the source to 0.0.0.0/0. This allows devices from all CIDR blocks to access the specified ports. If you know the IP address of the requester, we recommend that you set a specific IP range later. For more information, see Modify security group rules.

    1. Create a key pair

      1. A key pair serves as a secure credential to verify your identity when you log on. After you create a key pair, you must download the private key to connect to the ECS instance later. After the key pair is created, return to the ECS purchase page, refresh the page, and select the key pair.

      2. The root user has the highest permissions on the operating system. Using root as the logon name may cause security risks. We recommend that you select ecs-user as the logon name.

        Note

        After you create a key pair, the private key is automatically downloaded. You can check your browser's download history and save the private key file in .pem format.

    1. Create and view the ECS instance

      After you create or select the basic resources for the ECS instance, select the ECS Service Terms and ECS Subscription Unsubscription Rules checkboxes, and then click Confirm Order. In the success message that appears, click Management Console to view the created ECS instance in the console. Save the following information for later use.

      • Instance ID: Used to find the instance in the instance list.

      • Region: Used to find the instance in the instance list.

      • Public IP address: Used to verify the web service deployment on the ECS instance.

    Connect to the ECS instance
    1. On the Instance List page of the Elastic Compute Service Console, find the ECS instance that you created based on its region and instance ID, and click Remote Connection in the Actions column.

    2. In the Remote Connection dialog box, for Connect Via Workbench, click Log On Now.

    3. In the Log On To Instance dialog box, set Connection Method to Terminal Connection and Authentication Method to SSH Key Pair Authentication. Then, enter or upload the private key file that you downloaded when you created the key pair and click Log On to log on to the ECS instance with the username ecs-user.

      Note

      The private key file is automatically downloaded to your local computer when you create a key pair. You can check your browser's download history to find the private key file in .pem format.

    4. The following page indicates that you have successfully logged on to the ECS instance.

  2. Calculate the signature on the ECS server side.

    Important

    The server side provides two methods to obtain an STS temporary access credential and calculate a signature.

    • Obtain an STS temporary access credential and calculate a signature using an ECS instance that assumes a RAM role: The server side does not store AccessKey information. Instead, the ECS instance assumes a RAM role to access STS, obtain a temporary access credential, and calculate a signature. This method minimizes the risk of AccessKey pair leaks and offers higher security.

    • Obtain an STS temporary access credential and calculate a signature as a RAM user: The server side needs to store AccessKey information. It accesses STS using the RAM user's AccessKey pair and the ARN of the assumed RAM role, which are configured in the server's environment variables. It then obtains a temporary access credential and calculates a signature. This method is less secure.

    Obtain an STS temporary access credential and calculate a signature by having an ECS instance assume a RAM role

    Note
    • ECS is a cloud server provided by Alibaba Cloud. The following code examples must be run in a cloud server environment. Local environments do not support these operations.

    • When you use ECS, you do not need to create a RAM user. You can simply grant a RAM role to the ECS instance. The instance can then assume the role to obtain an STS temporary access credential and calculate a signature.

    1. Attach a RAM role to the ECS instance.

      Procedure

      1. Go to the Create Role page in the RAM console.

      2. On the Create Role page, for Trusted Entity Type, select Alibaba Cloud Service. Then, for Trusted Entity Name, select Elastic Compute Service/ECS/ECS and click OK.

      3. In the Create Role dialog box, enter a role name and click OK.

      4. After the role is created, click Add Authorization. On the access policy page, select the AliyunOSSFullAccess permission and click Confirm Add Authorization.

        Note

        If you are familiar with access control, you can go to the Create Policy page to create a more precise custom policy based on your requirements. Then, you can grant the policy to the RAM role to prevent redundant permissions.

      5. Go to the Instances page in the ECS console. Select the region where the ECS instance is located. Find the destination instance, click the image icon in the Actions column, and then click Grant/Revoke RAM Role.

      6. In the Grant/Revoke RAM Role dialog box, select the target RAM Role to attach it to the ECS instance.

    2. Calculate the signature on the server side.

      Java

      Use the following example to calculate the V4 signature on the Java server side. For the complete sample project, deploy upload_server.zip. Note that this sample project is built with JDK 23 and Spring Boot 3.4.0. You may need to adjust it based on your environment to ensure that the code runs as expected.

      • Configure dependencies.

        <!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>credentials-java</artifactId>
            <version>0.3.4</version>
        </dependency>
        
        <dependency>
            <groupId>com.aliyun.kms</groupId>
            <artifactId>kms-transfer-client</artifactId>
            <version>0.1.0</version>
        </dependency>
        
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>
      • API operation examples

        package com.example.demo.controller;
        
        import com.example.demo.util.ECSGenerateSignature;
        import com.example.demo.util.RAMGenerateSignature;
        import com.fasterxml.jackson.core.JsonProcessingException;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        @RestController
        public class VxController {
        
            /**
             * Obtain temporary access credentials by having an ECS instance assume a RAM role, calculate the signature information, and return it to the mini program client.
             * @return
             * @throws JsonProcessingException
             */
            @GetMapping("/generate_signature")
            public String generate_signature() throws JsonProcessingException {
                ECSGenerateSignature ecsGenerateSignature = new ECSGenerateSignature();
                return ecsGenerateSignature.getSignature();
            }
        
        }
        
      • Sample signature information utility class.

        package com.example.demo.util;
        
        import com.aliyun.credentials.models.CredentialModel;
        import com.aliyun.oss.common.auth.Credentials;
        import com.aliyun.oss.common.auth.CredentialsProvider;
        import com.aliyun.oss.common.auth.DefaultCredentials;
        import com.aliyun.oss.common.utils.BinaryUtil;
        import com.fasterxml.jackson.core.JsonProcessingException;
        import com.fasterxml.jackson.databind.ObjectMapper;
        import org.apache.commons.codec.binary.Base64;
        
        import javax.crypto.Mac;
        import javax.crypto.spec.SecretKeySpec;
        import java.time.Instant;
        import java.time.ZoneId;
        import java.time.ZonedDateTime;
        import java.time.format.DateTimeFormatter;
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.List;
        import java.util.Map;
        
        /**
         * Obtain an STS temporary access credential and calculate a signature by having an ECS instance assume a RAM role.
         */
        public class ECSGenerateSignature {
        
            public String getSignature() throws JsonProcessingException {
        
                com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config();
                config.setType("ecs_ram_role");   // This is a static field. Do not change it.
                config.setRoleName("roleName");   // Replace with the name of the RAM role attached to the ECS instance in step a.
                final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config);
                // Create an anonymous inner class that implements the CredentialsProvider interface to provide the credentials required for Alibaba Cloud OSS operations.
                CredentialsProvider credentialsProvider = new CredentialsProvider() {
                    @Override
                    public void setCredentials(Credentials credentials) {
                    }
        
                    @Override
                    public Credentials getCredentials() {
                        CredentialModel credential = credentialsClient.getCredential();
                        return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken());
                    }
        
                };
        
                String accessKeyId = credentialsProvider.getCredentials().getAccessKeyId();   // Get the AccessKey ID.
                String secretAccessKey = credentialsProvider.getCredentials().getSecretAccessKey();   // Get the AccessKey secret.
                String securityToken = credentialsProvider.getCredentials().getSecurityToken();   // Get the token.
        
                // Format the request date.
                long now = System.currentTimeMillis() / 1000;
                ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
                ZonedDateTime dtObjPlus3h = dtObj.plusHours(3); 
                // Request time.
                DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
                String dtObj1 = dtObj.format(dtObj1Formatter);
                // Request date.
                DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                String dtObj2 = dtObj.format(dtObj2Formatter);
                // Request expiration time.
                DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);
        
                // Create the policy.
                // The example policy form fields list only the required fields. For more information about other fields, see https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
                ObjectMapper mapper = new ObjectMapper();
        
                Map<String, Object> policy = new HashMap<>();
                policy.put("expiration", expirationTime);
        
                List<Object> conditions = new ArrayList<>();
        
                Map<String, String> bucketCondition = new HashMap<>();
                bucketCondition.put("bucket", "bucketname");    // Replace <bucketname> with your actual bucket name.
                conditions.add(bucketCondition);
        
                Map<String, String> signatureVersionCondition = new HashMap<>();
                signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
                conditions.add(signatureVersionCondition);
        
                Map<String, String> credentialCondition = new HashMap<>();
                credentialCondition.put("x-oss-credential",  accessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request");  // Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                conditions.add(credentialCondition);
        
                Map<String, String> token = new HashMap<>();
                token.put("x-oss-security-token", securityToken);
                conditions.add(token);
        
                Map<String, String> dateCondition = new HashMap<>();
                dateCondition.put("x-oss-date", dtObj1);
                conditions.add(dateCondition);
        
                policy.put("conditions", conditions);
                String jsonPolicy = mapper.writeValueAsString(policy);
        
                // Construct the string-to-sign.
                String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        
                // Calculate the signing key.
                byte[] dateKey = hmacsha256(("aliyun_v4" + secretAccessKey).getBytes(), dtObj2);
                byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");  // Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
                byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        
                // Calculate the signature.
                byte[] result = hmacsha256(signingKey, stringToSign);
                String signature = BinaryUtil.toHex(result);
        
                Map<String, String> messageMap = new HashMap<>();
                messageMap.put("security_token", securityToken);
                messageMap.put("signature", signature);
                messageMap.put("x_oss_date", dtObj1);
                messageMap.put("x_oss_credential", accessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request");  // Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
                messageMap.put("policy", stringToSign);
                ObjectMapper objectMapper = new ObjectMapper();
                // Print the signature information to be returned to the client.
                System.out.println(objectMapper.writeValueAsString(messageMap));
                return objectMapper.writeValueAsString(messageMap);
            }
        
        
            /**
             * A static method to calculate the hash value for a given key and data using the HMAC-SHA256 algorithm.
             * @param key
             * @param data
             * @return
             */
            public static byte[] hmacsha256(byte[] key,String data){
                try {
                    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
                    Mac mac = Mac.getInstance("HmacSHA256");
                    mac.init(secretKeySpec);
                    byte[] hmacBytes = mac.doFinal(data.getBytes());
                    return hmacBytes;
                }catch (Exception e){
                    throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
                }
            }
        }
        

      Python

      Use the following example to calculate the V4 signature on the Python server side.

      • Configure dependencies.

        sudo pip install oss2  
        sudo pip install alibabacloud_credentials
      • Sample code.

        from flask import Flask, jsonify
        import base64
        import hmac
        import hashlib
        import os
        import datetime
        import json
        import time
        from alibabacloud_credentials.client import Client as CredClient
        from alibabacloud_credentials.models import Config as CredConfig
        
        app = Flask(__name__)
        
        
        def hmacsha256(key, data):
            """
            A function to calculate the HMAC-SHA-256 hash value.
        
            :param key: The key used to calculate the hash, in bytes.
            :param data: The data to be hashed, as a string.
            :return: The calculated HMAC-SHA-256 hash value, in bytes.
            """
            try:
                mac = hmac.new(key, data.encode(), hashlib.sha256)
                hmacBytes = mac.digest()
                return hmacBytes
            except Exception as e:
                raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")
        
        
        @app.route('/generate_signature', methods=['GET'])
        def generate_signature():
            """
            Handles requests to generate signature information, executes the relevant logic flow including obtaining environment variables, creating a policy, constructing the string-to-sign, and calculating the signature.
            Then, it returns the generated signature information.
            :return: A JSON-formatted response containing a dictionary of signature information, in the following format:
            {
                "policy": "policy_string",
                "x-oss-signature-version": "OSS4-HMAC-SHA256",
                "x-oss-credential": "accesskeyid/date/cn-hangzhou/oss/aliyun_v4_request",
                "x-oss-date": "request_time",
                "signature": "signature",
                "security_token": "security_token"
            }
            """
            credentialConfig = CredConfig(
                # This is a static field. Do not change it.
                type='ecs_ram_role',
                # Replace with the name of the RAM role attached to the ECS instance in step a.
                role_name='role_name'
            )
            credentialsClient = CredClient(credentialConfig)
            credential = credentialsClient.get_credential()
        
            # Get the AccessKey ID.
            accesskeyid = credential.access_key_id
            # Get the AccessKey secret.
            accesskeysecret = credential.access_key_secret
            # Get the token.
            security_token = credential.security_token
        
            now = int(time.time())
        
            # Convert the timestamp to a datetime object.
            dt_obj = datetime.datetime.utcfromtimestamp(now)
            # Add 3 hours to the current time to set the request expiration time.
            dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
        
            # Request time.
            dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
            # Request date.
            dt_obj_2 = dt_obj.strftime('%Y%m%d')
            # Request expiration time.
            expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
        
            # Step 1: Create the policy.
            # The example policy form fields list only the required fields. For more information about other fields, see https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
            policy = {
                "expiration": expiration_time,
                "conditions": [
                    {"bucket": "bucket_name"},   # Replace <bucket_name> with your actual bucket name.
                    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
                    {"x-oss-credential": f"{accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},    # Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                    {"x-oss-security-token": security_token},
                    {"x-oss-date": dt_obj_1},
                ]
            }
            policy_str = json.dumps(policy).strip()
        
            # Step 2: Construct the string-to-sign.
            stringToSign = base64.b64encode(policy_str.encode()).decode()
        
            # Step 3: Calculate the signing key.
            dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).encode(), dt_obj_2)
            dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")    # Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
            dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
            signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
        
            # Step 4: Calculate the signature.
            result = hmacsha256(signingKey, stringToSign)
            signature = result.hex()
        
            return jsonify({
                "policy": stringToSign,  # Form field.
                "x_oss_signature_version": "OSS4-HMAC-SHA256",  # Specifies the signature version and algorithm. The value is fixed to OSS4-HMAC-SHA256.
                "x_oss_credential": f"{accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request",  # Specifies the parameter set for deriving the key. Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                "x_oss_date": dt_obj_1,  # The request time.
                "signature": signature,  # The signature authentication description.
                "security_token": security_token  # The security token.
            })
        
        
        if __name__ == "__main__":
            app.run(host='127.0.0.1', port=5000)  # To listen on other addresses such as 0.0.0.0, you must add an authentication mechanism on the server side.

      Node.js

      Use the following example to calculate the V4 signature on the Node.js server side.

      • Configure dependencies.

        npm install ali-oss
        npm install @alicloud/credentials
        npm install express
      • Sample code.

        const express = require('express');
        const OSS = require('ali-oss');
        const Credential = require('@alicloud/credentials');
        const { getCredential } = require('ali-oss/lib/common/signUtils');
        const { getStandardRegion } = require('ali-oss/lib/common/utils/getStandardRegion');
        const { policy2Str } = require('ali-oss/lib/common/utils/policy2Str');
        
        const app = express();
        const PORT = process.env.PORT || 5000; // The service request port.
        
        const ECSGenerateSignature = async () => {
            // Initialize the ECS RAM role credentials.
            const credentialsConfig = new Credential.Config({
                type: 'ecs_ram_role',  // This is a static field. Do not change it.
                roleName: 'role_name', // Replace with the name of the role assumed by the ECS instance.
            });
            const credentialClient = new Credential.default(credentialsConfig);
            const { accessKeyId, accessKeySecret, securityToken } = await credentialClient.getCredential();
        
            // Initialize the OSS client.
            const client = new OSS({
                bucket: 'bucketname', // Replace with the destination bucket name.
                region: 'cn-hangzhou', // Replace with the region of the destination bucket.
                accessKeyId,
                accessKeySecret,
                stsToken: securityToken,
                refreshSTSTokenInterval: 0,
                refreshSTSToken: async () => {
                    const { accessKeyId, accessKeySecret, securityToken } = await credentialClient.getCredential();
                    return { accessKeyId, accessKeySecret, stsToken: securityToken };
                },
            });
            
            // Create a form data map.
            const formData = new Map();
        
            // Set the signature expiration time to 10 minutes from the current time. 
            const date = new Date();
            const expirationDate = new Date(date);
            expirationDate.setMinutes(date.getMinutes() + 10);
            
            // Format the date into a UTC time string that conforms to the ISO 8601 standard.
            function padTo2Digits(num) {
                return num.toString().padStart(2, '0');
            }
            function formatDateToUTC(date) {
                return (
                    date.getUTCFullYear() +
                    padTo2Digits(date.getUTCMonth() + 1) +
                    padTo2Digits(date.getUTCDate()) +
                    'T' +
                    padTo2Digits(date.getUTCHours()) +
                    padTo2Digits(date.getUTCMinutes()) +
                    padTo2Digits(date.getUTCSeconds()) +
                    'Z'
                );
            }
            const formattedDate = formatDateToUTC(expirationDate);
            
            // Generate x-oss-credential and set the form data.
            const credential = getCredential(formattedDate.split('T')[0], getStandardRegion(client.options.region), client.options.accessKeyId);
            formData.set('x_oss_date', formattedDate);
            formData.set('x_oss_credential', credential);
            formData.set('x_oss_signature_version', 'OSS4-HMAC-SHA256');
        
            // Create the policy.
            // The example policy form fields list only the required fields. For more information about other fields, see Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
            const policy = {
                expiration: expirationDate.toISOString(),
                conditions: [
                    { 'bucket':"bucketname"}, // Replace "bucketname" with the destination bucket name.
                    { 'x-oss-credential': credential },
                    { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
                    { 'x-oss-date': formattedDate },
                ],
            };
            
            // If an STS token exists, add it to the policy and form data.
            if (client.options.stsToken) {
                policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
                formData.set('security_token', client.options.stsToken);
            }
        
            // Generate the signature and set the form data.
            const signature = client.signPostObjectPolicyV4(policy, date);
            formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
            formData.set('signature', signature);
        
            // Return the form data.
            return Object.fromEntries(formData);
        };
        
        app.get('/generate_signature', async (req, res) => {
            try {
                const result = await ECSGenerateSignature();
                res.json(result); // Return the generated signature data.
            } catch (error) {
                console.error('Error generating signature:', error);
                res.status(500).send('Error generating signature');
            }
        });
        
        app.listen(PORT, () => {
            console.log(`Server is running on http://localhost:${PORT}`);
        });
        

      Go

      Use the following example to calculate the V4 signature on the Go server side.

      • Configure dependencies.

        go get -u github.com/aliyun/credentials-go
        go mod tidy
      • Sample code.

        package main
        
        import (
        	"crypto/hmac"
        	"crypto/sha256"
        	"encoding/base64"
        	"encoding/hex"
        	"encoding/json"
        	"fmt"
        	"github.com/aliyun/credentials-go/credentials"
        	"hash"
        	"io"
        	"log"
        	"net/http"
        	"os"
        	"time"
        )
        
        // Define global variables.
        var (
        	region     string
        	bucketName string
        	product    = "oss"
        )
        
        // The PolicyToken struct is used to store the generated form data. 
        type PolicyToken struct {
        	Policy           string `json:"policy"`
        	SecurityToken    string `json:"security_token"`
        	SignatureVersion string `json:"x_oss_signature_version"`
        	Credential       string `json:"x_oss_credential"`
        	Date             string `json:"x_oss_date"`
        	Signature        string `json:"signature"`
        }
        
        func main() {
                // Define the default IP and port string.
        	strIPPort := ":5000"
        	if len(os.Args) == 3 {
        		strIPPort = fmt.Sprintf("%s:%s", os.Args[1], os.Args[2])
        	} else if len(os.Args) != 1 {
        		fmt.Println("Usage   : go run callbackserver.go                ")
        		fmt.Println("Usage   : go run callbackserver.go ip port        ")
        		fmt.Println("Example : go run callbackserver.go 11.22.**.** 80 ")
        		fmt.Println("Example : go run callbackserver.go 127.0.0.1 5000 ")  // To listen on other addresses such as 0.0.0.0, you must add an authentication mechanism on the server side.
        		fmt.Println("")
        		os.Exit(0)
        	}
        	// Print the address and port on which the server is running.
        	fmt.Printf("server is running on %s \n", strIPPort)
        	 // Register the function to handle requests to the root path.
        	http.HandleFunc("/", handlerRequest)
        	// Start the HTTP server.
        	err := http.ListenAndServe(strIPPort, nil)
        	if err != nil {
        		strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
        		panic(strError)
        	}
        }
        
        // The handlerRequest function handles HTTP requests.
        func handlerRequest(w http.ResponseWriter, r *http.Request) {
        	if r.Method == "GET" {
        		response := get_policy_token()
        		w.Header().Set("Access-Control-Allow-Methods", "POST")
        		// Set the allowed origin to all (this poses a security risk and should be used with caution in a production environment).
        		w.Header().Set("Access-Control-Allow-Origin", "*")
        		io.WriteString(w, response)
        	}
        }
        
        func get_policy_token() string {
                // Set the region of the bucket.
        	region = "cn-hangzhou"
        	// Set the bucket name.
        	bucketName = "bucketName"
        
                // Create an Alibaba Cloud credential configuration.
        	config := new(credentials.Config).
                        // Specify the credential type. The value is fixed to ecs_ram_role.
        		SetType("ecs_ram_role").
        		// Specify the name of the RAM role assumed by the ECS instance.
        		SetRoleName("roleName").
                        // Optional parameter. Disables IMDSv1. We recommend that you enable this parameter.
        		SetDisableIMDSv1(true)
        
                // Create a credential provider based on the configuration.
        	provider, err := credentials.NewCredential(config)
        	if err != nil {
        		log.Fatalf("NewCredential fail, err:%v", err)
        	}
                
                // Obtain credentials from the credential provider.
        	cred, err := provider.GetCredential()
        	if err != nil {
        		log.Fatalf("GetCredential fail, err:%v", err)
        	}
        	// Build the policy.
        	utcTime := time.Now().UTC()
        	date := utcTime.Format("20060102")
        	// Set the signature to expire one hour from the current time.
        	expiration := utcTime.Add(1 * time.Hour)
        	// The example policy form fields list only some of the required fields. For more information about other fields, see Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
        	policyMap := map[string]any{
        		"expiration": expiration.Format("2006-01-02T15:04:05.000Z"),
        		"conditions": []any{
        			map[string]string{"bucket": bucketName},
        			map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
        			map[string]string{"x-oss-credential": fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request",*cred.AccessKeyId, date, region, product)},
        			map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
        			map[string]string{"x-oss-security-token": *cred.SecurityToken},
        		},
        	}
        
                // Convert the policy to the JSON format.
        	policy, err := json.Marshal(policyMap)
        	if err != nil {
        		log.Fatalf("json.Marshal fail, err:%v", err)
        	}
        
        	 // Construct the string-to-sign.
        	stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
        	
        	hmacHash := func() hash.Hash { return sha256.New() }
                // Build the signing key.
        	signingKey := "aliyun_v4" + *cred.AccessKeySecret
        	h1 := hmac.New(hmacHash, []byte(signingKey))
        	io.WriteString(h1, date)
        	h1Key := h1.Sum(nil)
        
        	h2 := hmac.New(hmacHash, h1Key)
        	io.WriteString(h2, region)
        	h2Key := h2.Sum(nil)
        
        	h3 := hmac.New(hmacHash, h2Key)
        	io.WriteString(h3, product)
        	h3Key := h3.Sum(nil)
        
        	h4 := hmac.New(hmacHash, h3Key)
        	io.WriteString(h4, "aliyun_v4_request")
        	h4Key := h4.Sum(nil)
        
        	// Generate the signature.
        	h := hmac.New(hmacHash, h4Key)
        	io.WriteString(h, stringToSign)
        	signature := hex.EncodeToString(h.Sum(nil))
                
                // Build the form to be returned to the frontend.
        	policyToken := PolicyToken{
        		Policy: stringToSign,
        		Credential: fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request",*cred.AccessKeyId, date, region, product),
        		SignatureVersion: "OSS4-HMAC-SHA256",
        		Signature:        signature,
        		Date:             utcTime.UTC().Format("20060102T150405Z"),
        		SecurityToken:    *cred.SecurityToken,
        	}
        	response, err := json.Marshal(policyToken)
        	if err != nil {
        		fmt.Println("json err:", err)
        	}
        	fmt.Println(string(response))
        	// Return the form.
        	return string(response)
        }
        

      PHP

      Use the following example to calculate the V4 signature on the PHP server side.

      • Configure dependencies.

        composer require alibabacloud/credentials
      • Sample code.

        <?php
        require_once 'vendor/autoload.php';
        
        use AlibabaCloud\Credentials\Credential;
        
        // Set the region of the bucket.
        $region = 'cn-hangzhou';
        // Set the bucket name.
        $bucket = 'bucketName';
        $product = 'oss';
        
        // Create an Alibaba Cloud credential configuration.
        $config = new Credential\Config([
            // Specify the credential type. The value is fixed to ecs_ram_role.
            'type' => 'ecs_ram_role',
            // Set the name of the RAM role for the ECS instance.
            'roleName' => "roleName",
        ]);
        // Create a credential object based on the configuration.
        $credential = new Credential($config);
        // Obtain credential information from the credential object.
        $cred = $credential->getCredential();
        // Get the current UTC time.
        $utcTime = new DateTime('now', new DateTimeZone('UTC'));
        // Format the current date to Ymd, for example, 20240101.
        $date = $utcTime->format('Ymd');
        // Clone the current time object to set the expiration time.
        $expiration = clone $utcTime;
        // Set the expiration time to 1 hour from the current time.
        $expiration->add(new DateInterval('PT1H'));
        // Build the policy.
        // The example policy form fields list only some of the required fields. For more information about other fields, see Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
        $policyMap = [
            "expiration" => $expiration->format('Y-m-d\TH:i:s.000\Z'),
            "conditions" => [
                ["bucket" => $bucket],
                ["x-oss-signature-version" => "OSS4-HMAC-SHA256"],
                ["x-oss-credential" => sprintf("%s/%s/%s/%s/aliyun_v4_request",$cred->getAccessKeyId(), $date, $region, $product)],
                ["x-oss-date" => $utcTime->format('Ymd\THis\Z')],
                ["x-oss-security-token" => $cred->getSecurityToken()],
            ],
        ];
        // Convert the policy to a JSON-formatted string.
        $policy = json_encode($policyMap);
        // Base64-encode the policy string to get the string-to-sign.
        $stringToSign = base64_encode($policy);
        // Build the signing key by concatenating the fixed string "aliyun_v4" and the AccessKey secret.
        $signingKey = "aliyun_v4" . $cred->getAccessKeySecret();
        $h1Key = hmacSign($signingKey, $date);
        $h2Key = hmacSign($h1Key, $region);
        $h3Key = hmacSign($h2Key, $product);
        $h4Key = hmacSign($h3Key, "aliyun_v4_request");
        
        // Use h4Key to perform HMAC-SHA256 signing on the string-to-sign to get the final signature.
        $signature = hash_hmac('sha256', $stringToSign, $h4Key);
        
        // Build the form data to be returned to the frontend, including the policy, signature version, credential, date, signature, and security token.
        echo json_encode(array(
            'policy' => $stringToSign,
            "x_oss_signature_version" => "OSS4-HMAC-SHA256",
            "x_oss_credential" => sprintf("%s/%s/%s/%s/aliyun_v4_request",
            $cred->getAccessKeyId(), $date, $region, $product),
            "x_oss_date" => $utcTime->format('Ymd\THis\Z'),
            "signature" => $signature,
            "security_token" => $cred->getSecurityToken()
        ));
        
        // The hmacSign function, used for HMAC-SHA256 signature calculation.
        function hmacSign($key, $data)
        {
            return hash_hmac('sha256', $data, $key, true);
        }
        

    Obtain an STS temporary access credential and calculate a signature as a RAM user

    1. Grant permissions to the RAM user. For more information about how to create a RAM user, see Create a RAM user.

      Procedure

      1. Go to the RAM Users page, select the destination RAM user, and then click Add Permissions in the Actions column.

      2. Then, add the AliyunSTSAssumeRoleAccess permission (the permission to call the STS AssumeRole operation) to the permission policy.

    2. Grant permissions to the RAM role. For more information about how to create a RAM role, see Create a RAM role for a trusted Alibaba Cloud account.

      Procedure

      1. Go to the RAM Roles page, select the destination RAM role, and then click Add Permissions in the Actions column.

      2. Then, add the AliyunOSSFullAccess permission (the permission to manage OSS) to the permission policy. If you are familiar with access control, you can go to the Create Policy page to create a more precise custom policy based on your requirements. Then, you can grant the policy to the RAM role to prevent redundant permissions.

    3. Calculate the signature on the server side.

      Java

      Use the following example to calculate the V4 signature on the Java server side. For the complete sample project, deploy upload_server.zip. Note that this sample project is built with JDK 23 and Spring Boot 3.4.0. You may need to adjust it based on your environment to ensure that the code runs as expected.

      • Configure environment variables.

        Note
        • Replace <ALIBABA_CLOUD_ACCESS_KEY_ID> and <ALIBABA_CLOUD_ACCESS_KEY_SECRET> with the AccessKey ID and AccessKey secret of a RAM user, respectively. For more information about how to create an AccessKey ID and an AccessKey secret, see Create an AccessKey.

        • Replace <ROLE_ARN> with the ARN of the target role. On the Roles page, click the name of the target RAM role and find its ARN in the Basic Information section.

        • macOS/Linux/Unix systems.

          export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          export OSS_STS_ROLE_ARN=<ROLE_ARN>
        • Windows systems.

          set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          set OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Configure dependencies.

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>
      • Sample API operation.

        package com.example.demo.controller;
        
        import com.example.demo.util.ECSGenerateSignature;
        import com.example.demo.util.RAMGenerateSignature;
        import com.fasterxml.jackson.core.JsonProcessingException;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        @RestController
        public class VxController {
        
            /**
             * Obtain temporary access credentials using the AccessKey pair in the environment variables, calculate the signature information, and return it to the mini program client.
             * @return
             * @throws JsonProcessingException
             */
            @GetMapping("/generate_signature")
            public String generate_signature() throws JsonProcessingException {
                RAMGenerateSignature ramGenerateSignature = new RAMGenerateSignature();
                return ramGenerateSignature.getSignature();
            }
        
        }
        
      • Sample signature information utility class.

        package com.example.demo.util;
        
        import com.aliyun.oss.common.utils.BinaryUtil;
        import com.fasterxml.jackson.core.JsonProcessingException;
        import com.fasterxml.jackson.databind.ObjectMapper;
        import org.apache.commons.codec.binary.Base64;
        import com.aliyuncs.DefaultAcsClient;
        import com.aliyuncs.IAcsClient;
        import com.aliyuncs.auth.sts.AssumeRoleRequest;
        import com.aliyuncs.auth.sts.AssumeRoleResponse;
        import com.aliyuncs.exceptions.ClientException;
        import com.aliyuncs.profile.DefaultProfile;
        
        import javax.crypto.Mac;
        import javax.crypto.spec.SecretKeySpec;
        import java.time.Instant;
        import java.time.ZoneId;
        import java.time.ZonedDateTime;
        import java.time.format.DateTimeFormatter;
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.List;
        import java.util.Map;
        
        
        /**
         * Obtain a temporary access credential and calculate a signature using the AccessKey pair in the environment variables.
         */
        public class RAMGenerateSignature {
        
            public String getSignature() throws JsonProcessingException {
        
                // Obtain the basic information for sending an STS request.
                String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");    // Obtain the AccessKey ID from the environment variable.
                String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");    // Obtain the AccessKey secret from the environment variable.
                String roleArnForOssUpload = System.getenv("OSS_STS_ROLE_ARN");    // Obtain the ARN from the environment variable.
                String regionId = "cn-hangzhou";    // The region where the STS request is initiated.
                String roleSessionName = "<YOUR_ROLE_SESSION_NAME>";    // The role session name, used to distinguish different tokens. You can customize this.
                Long durationSeconds = 3600L;   // The validity period of the temporary access credential.
        
                // Initialize the client.
                DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
                IAcsClient client = new DefaultAcsClient(profile);
        
                AssumeRoleRequest request = new AssumeRoleRequest();
                request.setRoleArn(roleArnForOssUpload);
                request.setRoleSessionName(roleSessionName);
                request.setDurationSeconds(durationSeconds);
        
                // Define STS temporary access credential variables.
                String STSaccessKeyId = null;
                String STSsecretAccessKey = null;
                String securityToken = null;
        
                try {
                    AssumeRoleResponse response = client.getAcsResponse(request);
        
                    // Assign the STS temporary access credential returned from the request to custom variables.
                    STSaccessKeyId = response.getCredentials().getAccessKeyId();
                    STSsecretAccessKey = response.getCredentials().getAccessKeySecret();
                    securityToken = response.getCredentials().getSecurityToken();
        
                } catch (ClientException e) {
                    e.printStackTrace();
                }
        
                // Format the request date.
                long now = System.currentTimeMillis() / 1000;
                ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
                ZonedDateTime dtObjPlus3h = dtObj.plusHours(3);
                // Request time.
                DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
                String dtObj1 = dtObj.format(dtObj1Formatter);
                // Request date.
                DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                String dtObj2 = dtObj.format(dtObj2Formatter);
                // Request expiration time.
                DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);
        
                // Create the policy.
                // The example policy form fields list only the required fields. For more information about other fields, see https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
                ObjectMapper mapper = new ObjectMapper();
        
                Map<String, Object> policy = new HashMap<>();
                policy.put("expiration", expirationTime);
        
                List<Object> conditions = new ArrayList<>();
        
                Map<String, String> bucketCondition = new HashMap<>();
                bucketCondition.put("bucket", "bucketname");  // Replace <bucketname> with your actual bucket name.
                conditions.add(bucketCondition);
        
                Map<String, String> signatureVersionCondition = new HashMap<>();
                signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
                conditions.add(signatureVersionCondition);
        
                Map<String, String> credentialCondition = new HashMap<>();
                credentialCondition.put("x-oss-credential",  STSaccessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request");     // Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                conditions.add(credentialCondition);
        
                Map<String, String> token = new HashMap<>();
                token.put("x-oss-security-token", securityToken);
                conditions.add(token);
        
                Map<String, String> dateCondition = new HashMap<>();
                dateCondition.put("x-oss-date", dtObj1);
                conditions.add(dateCondition);
        
                policy.put("conditions", conditions);
                String jsonPolicy = mapper.writeValueAsString(policy);
        
                // Construct the string-to-sign.
                String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        
                // Calculate the signing key.
                byte[] dateKey = hmacsha256(("aliyun_v4" + STSsecretAccessKey).getBytes(), dtObj2);
                byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");    // Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
                byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        
                // Calculate the signature.
                byte[] result = hmacsha256(signingKey, stringToSign);
                String signature = BinaryUtil.toHex(result);
        
                Map<String, String> messageMap = new HashMap<>();
                messageMap.put("security_token", securityToken);
                messageMap.put("signature", signature);
                messageMap.put("x_oss_date", dtObj1);
                messageMap.put("x_oss_credential", STSaccessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request");    // Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
                messageMap.put("policy", stringToSign);
                ObjectMapper objectMapper = new ObjectMapper();
                // Print the signature information to be returned to the client.
        //        System.out.println(objectMapper.writeValueAsString(messageMap));
                return objectMapper.writeValueAsString(messageMap);
            }
        
            /**
             * A static method to calculate the hash value for a given key and data using the HMAC-SHA256 algorithm.
             * @param key
             * @param data
             * @return
             */
            public static byte[] hmacsha256(byte[] key,String data){
                try {
                    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
                    Mac mac = Mac.getInstance("HmacSHA256");
                    mac.init(secretKeySpec);
                    byte[] hmacBytes = mac.doFinal(data.getBytes());
                    return hmacBytes;
                }catch (Exception e){
                    throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
                }
            }
        }
        

      Python

      Use the following example to calculate the V4 signature on the Python server side.

      • Configure environment variables.

        Note
        • Replace <ALIBABA_CLOUD_ACCESS_KEY_ID> and <ALIBABA_CLOUD_ACCESS_KEY_SECRET> with the AccessKey ID and AccessKey secret of a RAM user, respectively. For more information about how to create an AccessKey ID and an AccessKey secret, see Create an AccessKey.

        • Replace <ROLE_ARN> with the ARN of the target role. On the Roles page, click the name of the target RAM role and find its ARN in the Basic Information section.

        • macOS/Linux/Unix

          export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          export OSS_STS_ROLE_ARN=<ROLE_ARN>
        • Windows

          set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          set OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Configure dependencies.

        pip install oss2  
        pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials
      • Sample code.

        from flask import Flask, jsonify
        import base64
        import hmac
        import hashlib
        import os
        import datetime
        import json
        import time
        from alibabacloud_tea_openapi.models import Config
        from alibabacloud_sts20150401.client import Client as Sts20150401Client
        from alibabacloud_sts20150401 import models as sts_20150401_models
        from alibabacloud_credentials.client import Client as CredentialClient
        import os
        
        app = Flask(__name__)
        
        def hmacsha256(key, data):
            """
            A function to calculate the HMAC-SHA-256 hash value.
        
            :param key: The key used to calculate the hash, in bytes.
            :param data: The data to be hashed, as a string.
            :return: The calculated HMAC-SHA-256 hash value, in bytes.
            """
            try:
                mac = hmac.new(key, data.encode(), hashlib.sha256)
                hmacBytes = mac.digest()
                return hmacBytes
            except Exception as e:
                raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")
        
        
        @app.route('/generate_signature', methods=['GET'])
        def generate_signature():
            """
            Handles requests to generate signature information, executes the relevant logic flow including obtaining environment variables, creating a policy, constructing the string-to-sign, and calculating the signature.
            Then, it returns the generated signature information.
            :return: A JSON-formatted response containing a dictionary of signature information, in the following format:
            {
                "policy": "policy_string",
                "x-oss-signature-version": "OSS4-HMAC-SHA256",
                "x-oss-credential": "accesskeyid/date/cn-hangzhou/oss/aliyun_v4_request",
                "x-oss-date": "request_time",
                "signature": "signature",
                "security_token": "security_token"
            }
            """
            access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
            access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
            role_arn_for_oss_upload = os.environ.get('OSS_STS_ROLE_ARN')
        
            # Custom session name.
            role_session_name = 'role_session_name'  
        
            # Specify the expiration time in seconds.
            expire_time = 3600  
        
            bucket = 'examplebucket'
            region_id = 'cn-hangzhou'
        
            # Initialize the configuration and pass the credentials directly.
            config = Config(
                region_id=region_id,
                access_key_id=access_key_id,
                access_key_secret=access_key_secret
            )
        
            # Create an STS client and obtain temporary credentials.
            sts_client = Sts20150401Client(config=config)
            assume_role_request = sts_20150401_models.AssumeRoleRequest(
                role_arn=role_arn_for_oss_upload,
                role_session_name=role_session_name
            )
            response = sts_client.assume_role(assume_role_request)
            token_data = response.body.credentials.to_map()
        
            # Use the temporary credentials returned by STS.
            sts_accesskeyid = token_data['AccessKeyId']
            sts_accesskeysecret = token_data['AccessKeySecret']
            security_token = token_data['SecurityToken']
        
            now = int(time.time())
        
            # Convert the timestamp to a datetime object.
            dt_obj = datetime.datetime.utcfromtimestamp(now)
            # Add 3 hours to the current time to set the request expiration time.
            dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
        
            # Request time.
            dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
            # Request date.
            dt_obj_2 = dt_obj.strftime('%Y%m%d')
            # Request expiration time.
            expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
        
            # Step 1: Create the policy.
            # The example policy form fields list only the required fields. For more information about other fields, see Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
            policy = {
                "expiration": expiration_time,
                "conditions": [
                    {"bucket": "bucket_name"},   # Replace <bucket_name> with your actual bucket name.
                    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
                    {"x-oss-credential": f"{sts_accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},    # Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                    {"x-oss-security-token": security_token},
                    {"x-oss-date": dt_obj_1},
                ]
            }
            policy_str = json.dumps(policy).strip()
        
            # Step 2: Construct the string-to-sign.
            stringToSign = base64.b64encode(policy_str.encode()).decode()
        
            # Step 3: Calculate the signing key.
            dateKey = hmacsha256(("aliyun_v4" + sts_accesskeysecret).encode(), dt_obj_2)
            dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")    # Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
            dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
            signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
        
            # Step 4: Calculate the signature.
            result = hmacsha256(signingKey, stringToSign)
            signature = result.hex()
        
            return jsonify({
                "policy": stringToSign,
                "x_oss_signature_version": "OSS4-HMAC-SHA256",
                "x_oss_credential": f"{sts_accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request",    # Replace <cn-hangzhou> with the region of your bucket. For example, for the China (Beijing) region, use cn-beijing.
                "x_oss_date": dt_obj_1,
                "signature": signature,
                "security_token": security_token
            })
        
        
        if __name__ == "__main__":
            app.run(host='127.0.0.1', port=5000)  # To listen on other addresses such as 0.0.0.0, you must add an authentication mechanism on the server side.

      Node.js

      Use the following example to calculate the V4 signature on the Node.js server side.

      • Configure environment variables.

        Note
        • Replace <ALIBABA_CLOUD_ACCESS_KEY_ID> and <ALIBABA_CLOUD_ACCESS_KEY_SECRET> with the AccessKey ID and AccessKey secret of a RAM user, respectively. For more information about how to create an AccessKey ID and an AccessKey secret, see Create an AccessKey.

        • Replace <ROLE_ARN> with the ARN of the target role. On the Roles page, click the name of the target RAM role and find its ARN in the Basic Information section.

        • macOS/Linux/Unix

          export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          export OSS_STS_ROLE_ARN=<ROLE_ARN>
        • Windows

          set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          set OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Configure dependencies.

        npm install ali-oss
        npm install @alicloud/credentials
        npm install express
      • Sample code.

        const express = require('express');
        const OSS = require('ali-oss');
        const { STS } = require('ali-oss');
        const Credential = require("@alicloud/credentials");
        const { getCredential } = require('ali-oss/lib/common/signUtils');
        const { getStandardRegion } = require('ali-oss/lib/common/utils/getStandardRegion');
        const { policy2Str } = require('ali-oss/lib/common/utils/policy2Str');
        
        const app = express();
        const PORT = process.env.PORT || 5000; // The service request port.
        
        const ECSGenerateSignature = async () => {
            // Initialize the STS client.
            let sts = new STS({
               accessKeyId : process.env.OSS_ACCESS_KEY_ID,  // Obtain the AccessKey ID of the RAM user from the environment variable.
               accessKeySecret : process.env.OSS_ACCESS_KEY_SECRET // Obtain the AccessKey secret of the RAM user from the environment variable.
            
            });
            // Call the assumeRole operation to obtain an STS temporary access credential.
            const result = await sts.assumeRole(process.env.OSS_STS_ROLE_ARN, '', '3600', 'sessiontest'); // Obtain the RAM role ARN from the environment variable, set the validity period of the temporary access credential to 3600 seconds, and the role session name to sessiontest (customizable).
        
            // Extract the AccessKeyId, AccessKeySecret, and SecurityToken from the temporary access credential.
            const accessKeyId = result.credentials.AccessKeyId;
            const accessKeySecret = result.credentials.AccessKeySecret;
            const securityToken = result.credentials.SecurityToken;
        
            // Initialize the OSS Client.
            const client = new OSS({
                bucket: 'bucketname', // Replace with the destination bucket name.
                region: 'cn-hangzhou', // Replace with the region of the destination bucket.
                accessKeyId,
                accessKeySecret,
                stsToken: securityToken,
                refreshSTSTokenInterval: 0,
                refreshSTSToken: async () => {
                    const { accessKeyId, accessKeySecret, securityToken } = await credentialClient.getCredential();
                    return { accessKeyId, accessKeySecret, stsToken: securityToken };
                },
            });
            
            // Create a form data map.
            const formData = new Map();
        
            // Set the signature expiration time to 10 minutes from the current time. 
            const date = new Date();
            const expirationDate = new Date(date);
            expirationDate.setMinutes(date.getMinutes() + 10);
            
            // Format the date into a UTC time string that conforms to the ISO 8601 standard.
            function padTo2Digits(num) {
                return num.toString().padStart(2, '0');
            }
            function formatDateToUTC(date) {
                return (
                    date.getUTCFullYear() +
                    padTo2Digits(date.getUTCMonth() + 1) +
                    padTo2Digits(date.getUTCDate()) +
                    'T' +
                    padTo2Digits(date.getUTCHours()) +
                    padTo2Digits(date.getUTCMinutes()) +
                    padTo2Digits(date.getUTCSeconds()) +
                    'Z'
                );
            }
            const formattedDate = formatDateToUTC(expirationDate);
        
            // Generate x-oss-credential and set the form data.
            const credential = getCredential(formattedDate.split('T')[0], getStandardRegion(client.options.region), client.options.accessKeyId);
            formData.set('x_oss_date', formattedDate);
            formData.set('x_oss_credential', credential);
            formData.set('x_oss_signature_version', 'OSS4-HMAC-SHA256');
        
            // Create the policy.
            // The example policy form fields list only the required fields. For more information about other fields, see https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
            const policy = {
                expiration: expirationDate.toISOString(),
                conditions: [
                    { 'bucket':"bucketname"}, // Replace "bucketname" with the destination bucket name.
                    { 'x-oss-credential': credential },
                    { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
                    { 'x-oss-date': formattedDate },
                ],
            };
        
            // If an STS token exists, add it to the policy and form data.
            if (client.options.stsToken) {
                policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
                formData.set('security_token', client.options.stsToken);
            }
        
            // Generate the signature and set the form data.
            const signature = client.signPostObjectPolicyV4(policy, date);
            formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
            formData.set('signature', signature);
        
            // Return the form data.
            return Object.fromEntries(formData);
        };
        
        app.get('/generate_signature', async (req, res) => {
            try {
                const result = await ECSGenerateSignature();
                res.json(result); // Return the generated signature data.
            } catch (error) {
                console.error('Error generating signature:', error);
                res.status(500).send('Error generating signature');
            }
        });
        
        app.listen(PORT, () => {
            console.log(`Server is running on http://localhost:${PORT}`);
        });
        

      Go

      Use the following example to calculate the V4 signature on the Go server side.

      • Configure environment variables.

        Note
        • Replace <ALIBABA_CLOUD_ACCESS_KEY_ID> and <ALIBABA_CLOUD_ACCESS_KEY_SECRET> with the AccessKey ID and AccessKey secret of a RAM user, respectively. For more information about how to create an AccessKey ID and an AccessKey secret, see Create an AccessKey.

        • Replace <ROLE_ARN> with the ARN of the target role. On the Roles page, click the name of the target RAM role and find its ARN in the Basic Information section.

        • macOS/Linux/Unix

          export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          export OSS_STS_ROLE_ARN=<ROLE_ARN>
        • Windows

          set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          set OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Configure dependencies.

        go get -u github.com/aliyun/credentials-go
        go mod tidy
      • Sample code.

        package main
        
        import (
        	"crypto/hmac"
        	"crypto/sha256"
        	"encoding/base64"
        	"encoding/hex"
        	"encoding/json"
        	"fmt"
        	"github.com/aliyun/credentials-go/credentials"
        	"hash"
        	"io"
        	"log"
        	"net/http"
        	"os"
        	"time"
        )
        
        // Define global variables.
        var (
        	region     string
        	bucketName string
        	product    = "oss"
        )
        
        // The PolicyToken struct is used to store the generated form data. 
        type PolicyToken struct {
        	Policy           string `json:"policy"`
        	SecurityToken    string `json:"security_token"`
        	SignatureVersion string `json:"x_oss_signature_version"`
        	Credential       string `json:"x_oss_credential"`
        	Date             string `json:"x_oss_date"`
        	Signature        string `json:"signature"`
        }
        
        func main() {
                // Define the default IP and port string.
        	strIPPort := ":8080"
        	if len(os.Args) == 3 {
        		strIPPort = fmt.Sprintf("%s:%s", os.Args[1], os.Args[2])
        	} else if len(os.Args) != 1 {
        		fmt.Println("Usage   : go run callbackserver.go                ")
        		fmt.Println("Usage   : go run callbackserver.go ip port        ")
        		fmt.Println("Example : go run callbackserver.go 11.22.**.** 80 ")
        		fmt.Println("Example : go run callbackserver.go 127.0.0.1 8080 ")  // To listen on other addresses such as 0.0.0.0, you must add an authentication mechanism on the server side.
        		fmt.Println("")
        		os.Exit(0)
        	}
        	// Print the address and port on which the server is running.
        	fmt.Printf("server is running on %s \n", strIPPort)
        	// Register the function to handle requests to the root path.
        	http.HandleFunc("/", handlerRequest)
        	// Start the HTTP server.
        	err := http.ListenAndServe(strIPPort, nil)
        	if err != nil {
        		strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
        		panic(strError)
        	}
        }
        
        // The handlerRequest function handles HTTP requests.
        func handlerRequest(w http.ResponseWriter, r *http.Request) {
        	if r.Method == "GET" {
        		response := get_policy_token()
        		w.Header().Set("Access-Control-Allow-Methods", "POST")
        		// Set the allowed origin to all (this poses a security risk and should be used with caution in a production environment).
        		w.Header().Set("Access-Control-Allow-Origin", "*")
        		io.WriteString(w, response)
        	}
        }
        
        func get_policy_token() string {
                // Set the region of the bucket.
          	region = "cn-hangzhou"
                // Set the bucket name.
        	bucketName = "bucketName"
        	config := new(credentials.Config).
        		// Specify the credential type. The value is fixed to ram_role_arn.
        		SetType("ram_role_arn").
        		// Obtain the AccessKey pair (AccessKeyId and AccessKeySecret) of the RAM user from the environment variables.
        		SetAccessKeyId(os.Getenv("OSS_ACCESS_KEY_ID")).
        		SetAccessKeySecret(os.Getenv("OSS_ACCESS_KEY_SECRET")).
        		// Obtain the ARN of the RAM role from the environment variable. This is the ID of the role to be assumed. The format is acs:ram::$accountID:role/$roleName.
        		SetRoleArn(os.Getenv("OSS_STS_ROLE_ARN")).
        		// Customize the role session name to distinguish different tokens.
        		SetRoleSessionName("Role_Session_Name").
        		// (Optional) Restrict the permissions of the STS token.
        		SetPolicy("").
        		// (Optional) Limit the validity period of the STS token.
        		SetRoleSessionExpiration(3600)
        
                 // Create a credential provider based on the configuration.
        	provider, err := credentials.NewCredential(config)
        	if err != nil {
        		log.Fatalf("NewCredential fail, err:%v", err)
        	}
        
                 // Obtain credentials from the credential provider.
        	cred, err := provider.GetCredential()
        	if err != nil {
        		log.Fatalf("GetCredential fail, err:%v", err)
        	}
        	// Build the policy.
        	utcTime := time.Now().UTC()
        	date := utcTime.Format("20060102")
        	// Set the signature to expire one hour from the current time.
        	expiration := utcTime.Add(1 * time.Hour)
        	// The example policy form fields list only some of the required fields. For more information about other fields, see Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
        	policyMap := map[string]any{
        		"expiration": expiration.Format("2006-01-02T15:04:05.000Z"),
        		"conditions": []any{
        			map[string]string{"bucket": bucketName},
        			map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
        			map[string]string{"x-oss-credential": fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request",*cred.AccessKeyId, date, region, product)},
        			map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
        			map[string]string{"x-oss-security-token": *cred.SecurityToken},
        		},
        	}
        
                // Convert the policy to the JSON format.
        	policy, err := json.Marshal(policyMap)
        	if err != nil {
        		log.Fatalf("json.Marshal fail, err:%v", err)
        	}
        
        	 // Construct the string-to-sign.
        	stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
        
        	hmacHash := func() hash.Hash { return sha256.New() }
                 // Build the signing key.
        	signingKey := "aliyun_v4" + *cred.AccessKeySecret
        	h1 := hmac.New(hmacHash, []byte(signingKey))
        	io.WriteString(h1, date)
        	h1Key := h1.Sum(nil)
        
        	h2 := hmac.New(hmacHash, h1Key)
        	io.WriteString(h2, region)
        	h2Key := h2.Sum(nil)
        
        	h3 := hmac.New(hmacHash, h2Key)
        	io.WriteString(h3, product)
        	h3Key := h3.Sum(nil)
        
        	h4 := hmac.New(hmacHash, h3Key)
        	io.WriteString(h4, "aliyun_v4_request")
        	h4Key := h4.Sum(nil)
        
        	// Generate the signature.
        	h := hmac.New(hmacHash, h4Key)
        	io.WriteString(h, stringToSign)
        	signature := hex.EncodeToString(h.Sum(nil))
        
                // Build the form to be returned to the frontend.
        	policyToken := PolicyToken{
        		Policy: stringToSign,
        		Credential: fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request",
        			*cred.AccessKeyId, date, region, product),
        		SignatureVersion: "OSS4-HMAC-SHA256",
        		Signature:        signature,
        		Date:             utcTime.UTC().Format("20060102T150405Z"),
        		SecurityToken:    *cred.SecurityToken,
        	}
        	response, err := json.Marshal(policyToken)
        	if err != nil {
        		fmt.Println("json err:", err)
        	}
        	fmt.Println(string(response))
        	// Return the form.
        	return string(response)
        }

      PHP

      Use the following example to calculate the V4 signature on the PHP server side.

      • Configure environment variables.

        Note
        • Replace <ALIBABA_CLOUD_ACCESS_KEY_ID> and <ALIBABA_CLOUD_ACCESS_KEY_SECRET> with the AccessKey ID and AccessKey secret of a RAM user, respectively. For more information about how to create an AccessKey ID and an AccessKey secret, see Create an AccessKey.

        • Replace <ROLE_ARN> with the ARN of the target role. On the Roles page, click the name of the target RAM role and find its ARN in the Basic Information section.

        • macOS/Linux/Unix

          export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          export OSS_STS_ROLE_ARN=<ROLE_ARN>
        • Windows

          set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
          set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
          set OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Configure dependencies.

        composer require alibabacloud/credentials
      • Sample code.

        <?php
        require_once 'vendor/autoload.php';
        
        use AlibabaCloud\Credentials\Credential;
        
        // Set the response header to JSON format.
        header('Content-Type: application/json');
        
        try {
            // Set the region of the bucket.
            $region = 'cn-hangzhou';
            // Set the bucket name.
            $bucket = 'bucketName';
            $product = 'oss';
        
            // Obtain credentials from environment variables.
            $accessKeyId = getenv('ALIBABA_CLOUD_ACCESS_KEY_ID');
            $accessKeySecret = getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET');
            $roleArn = getenv('ROLE_ARN');
        
            if (!$accessKeyId || !$accessKeySecret || !$roleArn) {
                throw new Exception('Environment variables are not configured correctly.');
            }
        
            // Create an Alibaba Cloud credential configuration.
            $config = new Credential\Config([
                'type' => 'ram_role_arn',
                'accessKeyId' => $accessKeyId,
                'accessKeySecret' => $accessKeySecret,
                'roleArn' => $roleArn,
                'roleSessionName' => 'role_session_name',
                'policy' => '',
                // Set the expiration time of the temporary access credential to 3600 seconds.
                'roleSessionExpiration' => 3600,
            ]);
        
            // Create a credential object based on the configuration.
            $credential = new Credential($config);
            // Obtain credential information from the credential object.
            $cred = $credential->getCredential();
        
            // Get the current UTC time.
            $utcTime = new DateTime('now', new DateTimeZone('UTC'));
            // Format the current date to Ymd, for example, 20240101.
            $date = $utcTime->format('Ymd');
            // Clone the current time object to set the expiration time.
            $expiration = clone $utcTime;
            // Set the expiration time to 1 hour from the current time.
            $expiration->add(new DateInterval('PT1H'));
            // Build the policy.
            // The example policy form fields list only some of the required fields. For more information about other fields, see Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend.
            $policyMap = [
                "expiration" => $expiration->format('Y-m-d\TH:i:s.000\Z'),
                "conditions" => [
                    ["bucket" => $bucket],
                    ["x-oss-signature-version" => "OSS4-HMAC-SHA256"],
                    ["x-oss-credential" => sprintf("%s/%s/%s/%s/aliyun_v4_request", $cred->getAccessKeyId(), $date, $region, $product)],
                    ["x-oss-date" => $utcTime->format('Ymd\THis\Z')],
                    ["x-oss-security-token" => $cred->getSecurityToken()],
                ],
            ];
            // Convert the policy to a JSON-formatted string.
            $policy = json_encode($policyMap);
            // Base64-encode the policy string to get the string-to-sign.
            $stringToSign = base64_encode($policy);
        
            // Build the signing key by concatenating the fixed string "aliyun_v4" and the AccessKey secret.
            $signingKey = "aliyun_v4" . $cred->getAccessKeySecret();
            $h1Key = hash_hmac('sha256', $date, $signingKey, true);
            $h2Key = hash_hmac('sha256', $region, $h1Key, true);
            $h3Key = hash_hmac('sha256', $product, $h2Key, true);
            $h4Key = hash_hmac('sha256', 'aliyun_v4_request', $h3Key, true);
        
            // Use h4Key to perform HMAC-SHA256 signing on the string-to-sign to get the final signature.
            $signature = hash_hmac('sha256', $stringToSign, $h4Key);
        
            // Build the form data to be returned to the frontend, including the policy, signature version, credential, date, signature, and security token.
            $responseData = [
                'policy' => $stringToSign,
                "x_oss_signature_version" => "OSS4-HMAC-SHA256",
                "x_oss_credential" => sprintf("%s/%s/%s/%s/aliyun_v4_request", $cred->getAccessKeyId(), $date, $region, $product),
                "x_oss_date" => $utcTime->format('Ymd\THis\Z'),
                "signature" => $signature,
                "security_token" => $cred->getSecurityToken()
            ];
        
            echo json_encode($responseData);
        
        } catch (Exception $e) {
            http_response_code(500);
            echo json_encode(['error' => $e->getMessage()]);
        }

Step 2: Configure the WeChat mini program

  1. To prevent WeChat from blocking requests from the mini program to OSS, you must configure the bucket domain name as a valid domain name on the WeChat mini program platform.

    1. Go to the Bucket List page. Select the destination bucket. In the navigation pane on the left, click Overview. In the Endpoint section, copy the Bucket Domain Name.

    2. Log on to the WeChat Official Accounts Platform and set the valid upload and download domain names to the public endpoint of the bucket, as shown in the figure.

      Note

      In a real-world business scenario, we recommend that you bind your custom domain name to the public endpoint provided by OSS. This lets you access files in your OSS bucket using the custom domain name. For more information about the configuration steps, see Bind a custom domain name.

  2. On the WeChat mini program client, use the V4 signature credential information obtained from the ECS server to send a request to upload a file to OSS.

    Note

    For more information about upload parameters, see Signature Version 4 and Form fields.

    The following is the sample code of the index.js file for uploading a file from the mini program client. For the complete sample project, deploy uploadoss.zip.

    Page({
      data: {
        key: 'filename.txt',  // The name of the file to be uploaded. You can also specify a directory for it. For example, to upload filename.txt to the youfolder directory, enter /youfolder/filename.txt.
        policy: '',
        xOssSecurityToken: '',
        xOssSignatureVersion: '',
        xOssCredential: '',
        xOssDate: '',
        xOssSignature: ''
      },
    
      // Method to upload the file. 
      uploadFileToOSS(filePath, callback) {
        const {
          key,
          policy,
          xOssSecurityToken,
          xOssSignatureVersion,
          xOssCredential,
          xOssDate,
          xOssSignature
        } = this.data;
        
        const apiUrl='http://<ECS instance public IP address>:<port>/generate_signature'   // Replace the IP address and port number with the actual public IP address and port number of your server. 
        // Send a request to obtain signature information. 
        wx.request({
          url: apiUrl,
          success: (res) => {
          
            this.data.xOssSignatureVersion = res.data.x_oss_signature_version;
            this.data.xOssCredential = res.data.x_oss_credential;
            this.data.xOssDate = res.data.x_oss_date;
            this.data.xOssSignature = res.data.signature;
            this.data.xOssSecurityToken = res.data.security_token;
            this.data.policy = res.data.policy;
            
            // This example lists only the required upload parameters. For more information about other parameters, see:
            // PostObject documentation: https://help.aliyun.com/zh/oss/developer-reference/postobject 
            // Signature Version 4 documentation: https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend
            const formData = {
              key,  // The name of the uploaded file.
              policy: this.data.policy,   // Form field.
              'x-oss-signature-version': this.data.xOssSignatureVersion,    // Specifies the signature version and algorithm.
              'x-oss-credential': this.data.xOssCredential,   // Specifies the parameter set for deriving the key.
              'x-oss-date': this.data.xOssDate,   // The request time.
              'x-oss-signature': this.data.xOssSignature,   // The signature authentication description.
              'x-oss-security-token': this.data.xOssSecurityToken,  // The security token.
              success_action_status: "200"  // The response status code after a successful upload.
            };
    
            // Send a request to upload the file. 
            wx.uploadFile({
              url: 'https://examplebucket.oss-cn-hangzhou.aliyuncs.com',  // This domain name is for example purposes only. Replace it with the domain name of your destination bucket.
              filePath: filePath,
              name: 'file',   // The value is fixed to file.
              formData: formData,
              success(res) {
                console.log('Upload response:', res);
                if (res.statusCode === 200) {
                  callback(null, res.data); // Upload successful.
                } else {
                  console.error('Upload failed, status code:', res.statusCode);
                  console.error('Failed response:', res);
                  callback(res); // Upload failed. Return the response.
                }
              },
              fail(err) {
                console.error('Upload failed:', err); // Output the error message.
                wx.showToast({ title: 'Upload failed. Please try again!', icon: 'none' });
                callback(err); // Call the callback to handle the error.
              }
            });
          },
          fail: (err) => {
            console.error('Failed to request the API operation:', err);
            wx.showToast({ title: 'Failed to obtain upload parameters. Please try again!', icon: 'none' });
          }
        });
      },
    
      // The code logic for uploading a file is triggered when the upload file button is clicked.  
      chooseAndUploadFile() {
        wx.chooseMessageFile({
          count: 1, // Select one file.
          type: 'all', // All file types are supported.
          success: (res) => {
            console.log('Selected file:', res.tempFiles); // Output the information of the selected file.
            if (res.tempFiles.length > 0) {
              const tempFilePath = res.tempFiles[0].path; // Get the path of the selected file.
              console.log('Selected file path:', tempFilePath); // Output the file path.
              this.uploadFileToOSS(tempFilePath, (error, data) => {
                if (error) {
                  wx.showToast({ title: 'Upload failed!', icon: 'none' });
                  console.error('Upload failed:', error); // Output the specific error message.
                } else {
                  wx.showToast({ title: 'Upload successful!', icon: 'success' });
                  console.log('Upload successful:', data); // Output the data after a successful upload.
                }
              });
            } else {
              wx.showToast({ title: 'No file selected!', icon: 'none' });
            }
          },
          fail: (err) => {
            wx.showToast({ title: 'Failed to select file!', icon: 'none' });
            console.error('Failed to select file:', err); // Output the error message for file selection.
          }
        });
      }
    });

Result verification

  1. After compiling and running the code, click Upload File on the WeChat mini program interface.

  2. On the Bucket List page, select the bucket to which the file was uploaded. In the upper-right corner, click Task List > Upload List. The file that you uploaded from the mini program is displayed in the upload list.