如何在微信小程序环境下将文件上传到OSS

更新时间:2025-03-03 07:42:59

微信小程序可以将图片、文档、视频等文件上传到OSS,实现文件的云端存储和分发。

方案概览

微信小程序上传文件到OSS的过程如下:

image

要实现微信小程序上传文件到OSS,只需两步:

  1. 配置服务端:在ECS,创建一个实例,用于从STS服务获取一个临时访问凭证,然后使用临时访问凭证为微信小程序生成上传文件到OSS所需的凭证签名。

  2. 配置微信小程序:在小程序平台,使用Bucket域名配置微信小程序的合法域名,确保小程序向OSS发送文件的请求不会被微信拦截;在微信小程序端,实现从ECS获取签名并使用签名上传文件到OSS的功能。

操作步骤

步骤一:配置服务端

说明

在实际部署时,如果您已经有自己的ECS服务器,则无需创建该ECS实例,可直接进行第2ECS服务端计算签名

  1. 创建并连接ECS实例。

    操作步骤

    创建ECS实例

    请您进入自定义购买页面,并根据如下各模块的内容,创建或选择购买ECS实例所需的基础资源。

    1. 选择地域 & 付费类型

      1. 根据业务需求,选择合适的付费类型。本文选择按量付费模式,此模式操作相对灵活。

      2. 基于业务场景对时延的要求,选择地域。通常来说离ECS实例的物理距离越近,网络时延越低,访问速度越快。本文以选择华东1(杭州)为例。

        image

    1. 创建专有网络VPC & 交换机

      创建VPC时,请您选择和ECS相同的地域,并根据业务需求规划网段。本文以创建华东1(杭州)地域的VPC和交换机为例。创建完毕后返回ECS购买页,刷新并选择VPC及交换机。

      说明

      创建VPC时,可同时创建交换机。

      image

      image

      image

    1. 选择规格 & 镜像

      选择实例的规格及镜像,镜像为实例确定安装的操作系统及版本。本文选择的实例规格为ecs.e-c1m1.large,在满足测试需求的同时,价格较为实惠。镜像为公共镜像Alibaba Cloud Linux 3.2104 LTS 64

      image

    1. 选择存储

      ECS实例选择系统盘,并按需选择数据盘。本文实现简单Web系统搭建,只需要系统盘存储操作系统,无需数据盘。

      image

    1. 绑定公网IP

      本实例需要支持公网访问。为了简化操作,本文选择直接为实例分配公网IP。您也可以在创建实例后,为实例绑定弹性公网IP,具体操作,请参见EIP绑定至ECS实例

      说明
      • 若未绑定公网IP,将无法使用SSHRDP通过公网直接访问实例,也无法通过公网验证实例中Web服务的搭建。

      • 本文选择按使用流量的带宽计费模式。此模式只需为所消耗的公网流量付费。更多信息,请参见公网带宽计费

      image

    1. 创建安全组

      为实例创建安全组。安全组是一种虚拟网络防火墙,能够控制ECS实例的出入流量。创建时,需要设置放行以下指定端口,便于后续访问ECS实例。

      端口范围:SSH(22)、RDP(3389)、HTTP(80)、HTTPS(443)。

      说明
      • 端口范围处选中的是ECS实例上运行的应用需开放的端口。

      • 此处创建的安全组默认设置0.0.0.0/0作为源的规则。0.0.0.0/0表示允许全网段设备访问指定的端口,如果您知道请求端的IP地址,建议后续设置为具体的IP范围。具体操作,请参见修改安全组规则

      image

    1. 创建密钥对

      1. 密钥对可作为登录时证明个人身份的安全凭证,创建完成后,必须下载私钥,以供后续连接ECS实例时使用。创建完毕后返回ECS购买页,刷新并选择密钥对。

      2. root具有操作系统的最高权限,使用root作为登录名可能会导致安全风险,建议您选择ecs-user作为登录名。

        说明

        创建密钥对后,私钥会自动下载,请您关注浏览器的下载记录,保存.pem格式的私钥文件。

        image

    1. 创建并查看ECS实例

      创建或选择好ECS实例所需的基础资源后,勾选《云服务器ECS服务条款》《云服务器ECS退订说明》,单击确认下单。在提示成功的对话框中,单击管理控制台,即可在控制台查看到创建好的ECS实例。请您保存以下数据,以便在后续操作中使用。

      • 实例ID:便于在实例列表中查询到该实例。

      • 地域:便于在实例列表中查询到该实例。

      • 公网IP地址:便于在后续使用ECS实例时,做Web服务的部署结果验证。

      imageimage

    连接ECS实例
    1. 云服务器ECS控制台实例列表页面,根据地域、实例ID找到创建好的ECS实例,单击操作列下的远程连接image

    2. 远程连接对话框中,单击通过Workbench远程连接对应的立即登录image

    3. 登录实例对话框中,选择认证方式SSH密钥认证,用户名为ecs-user,输入或上传创建密钥对时下载的私钥文件,单击确定,即可登录ECS实例。

      说明

      私钥文件在创建密钥对时自动下载到本地,请您关注浏览器的下载记录,查找.pem格式的私钥文件。

      image

    4. 显示如下页面后,即说明您已成功登录ECS实例。image

  2. ECS服务端计算签名。

    重要

    服务端提供了以下两种方式获取STS临时访问凭证并计算签名。

    • ECS扮演RAM角色获取STS临时访问凭证计算签名:服务端不保留AK信息,采用ECS扮演RAM角色的方式,去访问STS服务以获取临时访问凭证并计算签名,最大程度上降低了AK信息泄露的风险,安全性较高。

    • RAM用户获取STS临时访问凭证计算签名:服务端需要保留AK信息,通过获取配置于服务端环境变量里的RAM用户AK信息,以及所扮演RAM角色的ARN。进而访问STS服务获取临时访问凭证并计算签名,安全性较低。

    ECS扮演RAM角色获取STS临时访问凭证计算签名
    RAM用户获取STS临时访问凭证计算签名
    说明
    • ECS是阿里云提供的云服务器,下述代码示例需在云服务器环境中运行,本地环境不支持此类操作。

    • 使用ECS时,无需创建RAM用户,只需将RAM角色授予ECS实例,便可通过扮演该角色获取STS临时访问凭证并计算签名。

    1. ECS绑定RAM角色。

      操作步骤

      1. 进入RAM访问控制的创建角色页面。

      2. 在创建角色页面勾选阿里云服务,单击下一步

        image

      3. 勾选普通服务角色,填写角色名称并选择受信服务为云服务器后,单击完成,即可完成创建。

        image

      4. 创建完毕后单击为角色授权 > 新增授权,在权限策略中勾选ALiyunOSSFullAccess权限后单击确认新增授权

        说明

        倘若您对访问控制权限较为熟悉,那么可以直接进入创建权限策略页面,按需创建更为精准的自定义授权,随后将其授予RAM角色,以此防止权限出现冗余情况。

        image

      5. 进入云服务器ECS实例页面,在页面上方选择ECS实例所处地域,然后在实例页面单击目标实例右侧image按钮,单击授予/收回RAM角色

        image

      6. 授予/收回RAM角色弹出框选择目标RAM角色,完成ECS绑定RAM角色。

        image

    2. 服务端计算签名。

      Java
      Python
      Node.js
      Go
      PHP

      请参考以下示例完成Java服务端的V4签名计算。完整示例工程请部署upload_server.zip。请注意,此示例工程基于JDK 23Spring Boot 3.4.0构建,您参考时请根据自身环境合理调整,确保代码正常运行。

      • 配置依赖。

        <!-- 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接口示例。

        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 {
        
            /**
             * 使用ECS扮演RAM角色方式获取临时访问凭证,计算签名信息,返回小程序端。
             * @return
             * @throws JsonProcessingException
             */
            @GetMapping("/generate_signature")
            public String generate_signature() throws JsonProcessingException {
                ECSGenerateSignature ecsGenerateSignature = new ECSGenerateSignature();
                return ecsGenerateSignature.getSignature();
            }
        
        }
        
      • 签名信息工具类示例。

        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;
        
        /**
         * ECS扮演RAM角色方式获取STS临时访问凭证计算签名
         */
        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");   //固定值无需更改
                config.setRoleName("roleName");   //请替换为步骤a(ECS绑定RAM角色)中,ECS所绑定的RAM角色名称
                final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config);
                //创建一个匿名内部类实现CredentialsProvider接口,用于提供阿里云OSS操作所需的凭证信息
                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();   //获取AK
                String secretAccessKey = credentialsProvider.getCredentials().getSecretAccessKey();   //获取SK
                String securityToken = credentialsProvider.getCredentials().getSecurityToken();   //获取Token
        
                //格式化请求日期
                long now = System.currentTimeMillis() / 1000;
                ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
                ZonedDateTime dtObjPlus3h = dtObj.plusHours(3); 
                //请求时间
                DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
                String dtObj1 = dtObj.format(dtObj1Formatter);
                //请求日期
                DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                String dtObj2 = dtObj.format(dtObj2Formatter);
                //请求过期时间
                DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);
        
                // 创建policy
                // 示例policy表单域只列举必填字段,如有其他需求可参考文档: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");    //请将<bucketname>替换为您的实际Bucket名称
                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");  //请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为: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);
        
                //构造待签名字符串(StringToSign)
                String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        
                //计算SigningKey
                byte[] dateKey = hmacsha256(("aliyun_v4" + secretAccessKey).getBytes(), dtObj2);
                byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");  //请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
                byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        
                //计算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");  //请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
                messageMap.put("policy", stringToSign);
                ObjectMapper objectMapper = new ObjectMapper();
                //打印返回至客户端的签名信息
                System.out.println(objectMapper.writeValueAsString(messageMap));
                return objectMapper.writeValueAsString(messageMap);
            }
        
        
            /**
             * 使用HMAC-SHA256算法计算给定密钥和数据的哈希值的静态方法
             * @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服务端的V4签名计算。

      • 配置依赖。

        sudo pip install oss2  
        sudo pip install alibabacloud_credentials
      • 代码示例。

        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):
            """
            计算HMAC-SHA256哈希值的函数
        
            :param key: 用于计算哈希的密钥,字节类型
            :param data: 要进行哈希计算的数据,字符串类型
            :return: 计算得到的HMAC-SHA256哈希值,字节类型
            """
            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():
            """
            处理生成签名信息的请求,执行相关逻辑流程,包括获取环境变量、创建策略、构造待签名字符串、计算签名等操作,
            并返回生成的签名信息。
            :return: JSON格式的响应,包含签名信息的字典,格式如下:
            {
                "policy": "policy字符串",
                "x-oss-signature-version": "OSS4-HMAC-SHA256",
                "x-oss-credential": "accesskeyid/日期/cn-hangzhou/oss/aliyun_v4_request",
                "x-oss-date": "请求时间",
                "signature": "签名",
                "security_token": "安全令牌"
            }
            """
            credentialConfig = CredConfig(
                # 固定值无需更改
                type='ecs_ram_role',
                # 请替换为步骤a(ECS绑定RAM角色)中,ECS所绑定的RAM角色名称
                role_name='role_name'
            )
            credentialsClient = CredClient(credentialConfig)
            credential = credentialsClient.get_credential()
        
            # 获取AK
            accesskeyid = credential.access_key_id
            # 获取SK
            accesskeysecret = credential.access_key_secret
            # 获取Token
            security_token = credential.security_token
        
            now = int(time.time())
        
            # 将时间戳转换为datetime对象
            dt_obj = datetime.datetime.utcfromtimestamp(now)
            # 在当前时间增加3小时,设置为请求的过期时间
            dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
        
            # 请求时间
            dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
            # 请求日期
            dt_obj_2 = dt_obj.strftime('%Y%m%d')
            # 请求过期时间
            expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
        
            # 步骤1:创建policy。
            # 示例policy表单域只列举必填字段,如有其他需求可参考文档:https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend
            policy = {
                "expiration": expiration_time,
                "conditions": [
                    {"bucket": "bucket_name"},   #请将<bucket_name>替换为您的实际Bucket名称
                    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
                    {"x-oss-credential": f"{accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},    #请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                    {"x-oss-security-token": security_token},
                    {"x-oss-date": dt_obj_1},
                ]
            }
            policy_str = json.dumps(policy).strip()
        
            # 步骤2:构造待签名字符串(StringToSign)
            stringToSign = base64.b64encode(policy_str.encode()).decode()
        
            # 步骤3:计算SigningKey
            dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).encode(), dt_obj_2)
            dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")    #请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
            dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
            signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
        
            # 步骤4:计算Signature
            result = hmacsha256(signingKey, stringToSign)
            signature = result.hex()
        
            return jsonify({
                "policy": stringToSign,  #表单域
                "x_oss_signature_version": "OSS4-HMAC-SHA256",  #指定签名的版本和算法,固定值为OSS4-HMAC-SHA256
                "x_oss_credential": f"{accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request",  #指明派生密钥的参数集,请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                "x_oss_date": dt_obj_1,  #请求的时间
                "signature": signature,  #签名认证描述信息
                "security_token": security_token  #安全令牌
            })
        
        
        if __name__ == "__main__":
            app.run(host='0.0.0.0', port=5000)

      请参考以下示例完成Node.js服务端的V4签名计算。

      • 配置依赖。

        npm install ali-oss
        npm install @alicloud/credentials
        npm install express
      • 代码示例。

        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; //服务请求端口号
        
        const ECSGenerateSignature = async () => {
            //初始化ECS RAM角色凭证
            const credentialsConfig = new Credential.Config({
                type: 'ecs_ram_role',  // 固定值无需更改
                roleName: 'role_name', // 请替换为ECS扮演的角色名称
            });
            const credentialClient = new Credential.default(credentialsConfig);
            const { accessKeyId, accessKeySecret, securityToken } = await credentialClient.getCredential();
        
            // 初始化OSS客户端
            const client = new OSS({
                bucket: 'bucketname', // 请替换为目标Bucket名称
                region: 'cn-hangzhou', // 请替换为标Bucket所在地域
                accessKeyId,
                accessKeySecret,
                stsToken: securityToken,
                refreshSTSTokenInterval: 0,
                refreshSTSToken: async () => {
                    const { accessKeyId, accessKeySecret, securityToken } = await credentialClient.getCredential();
                    return { accessKeyId, accessKeySecret, stsToken: securityToken };
                },
            });
            
            // 创建表单数据Map
            const formData = new Map();
        
            // 设置签名过期时间为当前时间往后推10分钟 
            const date = new Date();
            const expirationDate = new Date(date);
            expirationDate.setMinutes(date.getMinutes() + 10);
            
            // 格式化日期为符合ISO 8601标准的UTC时间字符串格式
            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);
            
            // 生成x-oss-credential并设置表单数据
            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');
        
            // 创建policy
            // 示例policy表单域只列举必填字段,如有其他需求可参考签名版本4文档:https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend
            const policy = {
                expiration: expirationDate.toISOString(),
                conditions: [
                    { 'bucket':"bucketname"}, // "bucketname"请替换为目标bucket名称
                    { 'x-oss-credential': credential },
                    { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
                    { 'x-oss-date': formattedDate },
                ],
            };
            
            // 如果存在STS Token,添加到策略和表单数据中
            if (client.options.stsToken) {
                policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
                formData.set('security_token', client.options.stsToken);
            }
        
            // 生成签名并设置表单数据
            const signature = client.signPostObjectPolicyV4(policy, date);
            formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
            formData.set('signature', signature);
        
            // 返回表单数据
            return Object.fromEntries(formData);
        };
        
        app.get('/generate_signature', async (req, res) => {
            try {
                const result = await ECSGenerateSignature();
                res.json(result); // 返回生成的签名数据
            } 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服务端的V4签名计算。

      • 配置依赖。

        go get -u github.com/aliyun/credentials-go
        go mod tidy
      • 代码示例。

        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"
        )
        
        // 定义全局变量
        var (
        	region     string
        	bucketName string
        	product    = "oss"
        )
        
        // PolicyToken 结构体用于存储生成的表单数据 
        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() {
                // 定义默认的IP和端口字符串
        	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 0.0.0.0 5000 ")
        		fmt.Println("")
        		os.Exit(0)
        	}
        	// 打印服务器运行的地址和端口
        	fmt.Printf("server is running on %s \n", strIPPort)
        	 // 注册处理根路径请求的函数
        	http.HandleFunc("/", handlerRequest)
        	// 启动HTTP服务器
        	err := http.ListenAndServe(strIPPort, nil)
        	if err != nil {
        		strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
        		panic(strError)
        	}
        }
        
        // handlerRequest 函数处理HTTP请求
        func handlerRequest(w http.ResponseWriter, r *http.Request) {
        	if r.Method == "GET" {
        		response := get_policy_token()
        		w.Header().Set("Access-Control-Allow-Methods", "POST")
        		// 设置允许的源为所有(存在安全风险,生产环境需谨慎使用)
        		w.Header().Set("Access-Control-Allow-Origin", "*")
        		io.WriteString(w, response)
        	}
        }
        
        func get_policy_token() string {
                // 设置bucket所处地域
        	region = "cn-hangzhou"
        	// 设置bucket名称
        	bucketName = "bucketName"
        
                // 创建阿里云凭证配置
        	config := new(credentials.Config).
                        // 填写Credential类型,固定值为ram_role_arn
        		SetType("ecs_ram_role").
        		// 填写 ECS 实例所扮演的 RAM 角色名称
        		SetRoleName("roleName").
                        // 可选参数,禁用 IMDSv1,建议开启
        		SetDisableIMDSv1(true)
        
                // 根据配置创建凭证提供器
        	provider, err := credentials.NewCredential(config)
        	if err != nil {
        		log.Fatalf("NewCredential fail, err:%v", err)
        	}
                
                // 从凭证提供器获取凭证
        	cred, err := provider.GetCredential()
        	if err != nil {
        		log.Fatalf("GetCredential fail, err:%v", err)
        	}
        	// 构建policy
        	utcTime := time.Now().UTC()
        	date := utcTime.Format("20060102")
        	// 设置签名过期时间为当前时间起一个小时后过期
        	expiration := utcTime.Add(1 * time.Hour)
        	// 示例policy表单域只列举了部分必填字段,如有其他需求可参考签名版本4文档: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},
        		},
        	}
        
                // 将policy转换为 JSON 格式
        	policy, err := json.Marshal(policyMap)
        	if err != nil {
        		log.Fatalf("json.Marshal fail, err:%v", err)
        	}
        
        	 // 构造待签名字符串(StringToSign)
        	stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
        	
        	hmacHash := func() hash.Hash { return sha256.New() }
                // 构建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)
        
        	// 生成签名
        	h := hmac.New(hmacHash, h4Key)
        	io.WriteString(h, stringToSign)
        	signature := hex.EncodeToString(h.Sum(nil))
                
                // 构建返回给前端的表单
        	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 string(response)
        }
        

      请参考以下示例完成PHP服务端的V4签名计算。

      • 配置依赖。

        composer require alibabacloud/credentials
      • 代码示例。

        <?php
        require_once 'vendor/autoload.php';
        
        use AlibabaCloud\Credentials\Credential;
        
        // 设置bucket所处地域
        $region = 'cn-hangzhou';
        // 设置bucket名称
        $bucket = 'bucketName';
        $product = 'oss';
        
        // 创建阿里云凭证配置
        $config = new Credential\Config([
            // 填写Credential类型,固定值为ecs_ram_role。
            'type' => 'ecs_ram_role',
            // 设置 ECS 实例的 RAM 角色名称
            'roleName' => "roleName",
        ]);
        // 根据配置创建凭证对象
        $credential = new Credential($config);
        // 从凭证对象中获取凭证信息
        $cred = $credential->getCredential();
        // 获取当前的 UTC 时间
        $utcTime = new DateTime('now', new DateTimeZone('UTC'));
        // 格式化当前日期为 Ymd 格式,例如 20240101
        $date = $utcTime->format('Ymd');
        // 克隆当前时间对象,用于设置过期时间
        $expiration = clone $utcTime;
        // 设置过期时间为当前时间往后 1 小时
        $expiration->add(new DateInterval('PT1H'));
        // 构建policy
        // 示例policy表单域只列举了部分必填字段,如有其他需求可参考签名版本4文档: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()],
            ],
        ];
        // 将policy转换为 JSON 格式的字符串
        $policy = json_encode($policyMap);
        // 对policy字符串进行 Base64 编码,得到待签名的字符串
        $stringToSign = base64_encode($policy);
        // 构建signingKey,由固定字符串 "aliyun_v4" 和访问密钥 Secret 拼接而成
        $signingKey = "aliyun_v4" . $cred->getAccessKeySecret();
        $h1Key = hmacSign($signingKey, $date);
        $h2Key = hmacSign($h1Key, $region);
        $h3Key = hmacSign($h2Key, $product);
        $h4Key = hmacSign($h3Key, "aliyun_v4_request");
        
        // 使用 h4Key 对待签名的字符串进行 HMAC-SHA256 签名,得到最终的签名
        $signature = hash_hmac('sha256', $stringToSign, $h4Key);
        
        // 构建响应给前端的表单数据,包含policy、签名版本、凭证、日期、签名和安全令牌等信息
        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()
        ));
        
        // hmacSign 函数,用于进行 HMAC-SHA256 签名计算
        function hmacSign($key, $data)
        {
            return hash_hmac('sha256', $data, $key, true);
        }
        
    1. RAM用户授权。有关如何创建RAM用户,请参见创建RAM用户

      操作步骤

      1. 进入RAM用户页面,选择目标RAM用户后单击右侧添加权限

        image

      2. 接着在权限策略处添加AliyunSTSAssumeRoleAccess权限(调用STS服务AssumeRole接口的权限)。

        image

    2. RAM角色授权。有关如何创建RAM角色,请参见创建可信实体为阿里云账号的RAM角色

      操作步骤

      1. 进入RAM角色页面,选择目标RAM角色后单击右侧新增授权

        image

      2. 接着在权限策略处添加AliyunOSSFullAccess权限(管理对象存储服务(OSS)权限)。若您对访问控制权限较为熟悉,那么可以直接进入创建权限策略页面,按需创建更为精准的自定义授权,随后将其授予RAM角色,以此防止出现权限冗余情况。

        image

    3. 服务端计算签名。

      Java
      Python
      Node.js
      Go
      PHP

      请参考以下示例完成Java服务端的V4签名计算。完整示例工程请部署upload_server.zip。请注意,此示例工程基于JDK 23Spring Boot 3.4.0构建,您参考时请根据自身环境合理调整,确保代码正常运行。

      • 配置环境变量。

        说明
        • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>请分别替换为RAM用户的AccessKey ID、AccessKeySecret。如何创建AccessKey IDAccessKeySecret请参见创建AccessKey

        • <ROLE_ARN>请替换为目标角色ARN,在角色页面单击目标RAM角色名称,然后在基本信息区域查看对应的ARN。

        • 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>
      • 配置依赖。

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>
      • API接口示例。

        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 {
        
            /**
             * 使用环境变量中的AK获取临时访问凭证,计算签名信息,返回小程序端。
             * @return
             * @throws JsonProcessingException
             */
            @GetMapping("/generate_signature")
            public String generate_signature() throws JsonProcessingException {
                RAMGenerateSignature ramGenerateSignature = new RAMGenerateSignature();
                return ramGenerateSignature.getSignature();
            }
        
        }
        
      • 签名信息工具类示例。

        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;
        
        
        /**
         * 使用环境变量中的AK获取临时访问凭证计算签名
         */
        public class RAMGenerateSignature {
        
            public String getSignature() throws JsonProcessingException {
        
                //获取发送STS请求基础信息
                String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");    //环境变量中获取access_key_id
                String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");    //环境变量中获取access_key_secret
                String roleArnForOssUpload = System.getenv("OSS_STS_ROLE_ARN");    //环境变量中获取ARN
                String regionId = "cn-hangzhou";    //发起STS请求所在的地域
                String roleSessionName = "<YOUR_ROLE_SESSION_NAME>";    //色会话名称,用来区分不同的令牌,可自定义
                Long durationSeconds = 3600L;   //临时访问凭证的有效时间
        
                //初始化客户端
                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);
        
                //定义STS临时访问凭证变量
                String STSaccessKeyId = null;
                String STSsecretAccessKey = null;
                String securityToken = null;
        
                try {
                    AssumeRoleResponse response = client.getAcsResponse(request);
        
                    //将请求返回的STS临时访问凭证赋值到自定义变量中
                    STSaccessKeyId = response.getCredentials().getAccessKeyId();
                    STSsecretAccessKey = response.getCredentials().getAccessKeySecret();
                    securityToken = response.getCredentials().getSecurityToken();
        
                } catch (ClientException e) {
                    e.printStackTrace();
                }
        
                //格式化请求日期
                long now = System.currentTimeMillis() / 1000;
                ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
                ZonedDateTime dtObjPlus3h = dtObj.plusHours(3);
                //请求时间
                DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
                String dtObj1 = dtObj.format(dtObj1Formatter);
                //请求日期
                DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                String dtObj2 = dtObj.format(dtObj2Formatter);
                //请求过期时间
                DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);
        
                // 创建policy
                // 示例policy表单域只列举必填字段,如有其他需求可参考文档: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");  //请将<bucketname>替换为您的实际Bucket名称
                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");     //请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为: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);
        
                //构造待签名字符串(StringToSign)
                String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        
                //计算SigningKey
                byte[] dateKey = hmacsha256(("aliyun_v4" + STSsecretAccessKey).getBytes(), dtObj2);
                byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");    //请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
                byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        
                //计算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");    //请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
                messageMap.put("policy", stringToSign);
                ObjectMapper objectMapper = new ObjectMapper();
                //打印返回至客户端的签名信息
        //        System.out.println(objectMapper.writeValueAsString(messageMap));
                return objectMapper.writeValueAsString(messageMap);
            }
        
            /**
             * 使用HMAC-SHA256算法计算给定密钥和数据的哈希值的静态方法
             * @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服务端的V4签名计算。

      • 配置环境变量。

        说明
        • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>请分别替换为RAM用户的AccessKey ID、AccessKeySecret。如何创建AccessKey IDAccessKeySecret请参见创建AccessKey

        • <ROLE_ARN>请替换为目标角色ARN,在角色页面单击目标RAM角色名称,然后在基本信息区域查看对应的ARN。

        • 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>
      • 配置依赖。

        pip install oss2  
        pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials
      • 代码示例。

        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):
            """
            计算HMAC-SHA256哈希值的函数
        
            :param key: 用于计算哈希的密钥,字节类型
            :param data: 要进行哈希计算的数据,字符串类型
            :return: 计算得到的HMAC-SHA256哈希值,字节类型
            """
            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():
            """
            处理生成签名信息的请求,执行相关逻辑流程,包括获取环境变量、创建策略、构造待签名字符串、计算签名等操作,
            并返回生成的签名信息。
            :return: JSON格式的响应,包含签名信息的字典,格式如下:
            {
                "policy": "policy字符串",
                "x-oss-signature-version": "OSS4-HMAC-SHA256",
                "x-oss-credential": "accesskeyid/日期/cn-hangzhou/oss/aliyun_v4_request",
                "x-oss-date": "请求时间",
                "signature": "签名",
                "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')
        
            # 自定义会话名称
            role_session_name = 'role_session_name'  
        
            # 指定过期时间,单位为秒
            expire_time = 3600  
        
            bucket = 'examplebucket'
            region_id = 'cn-hangzhou'
        
            # 初始化配置,直接传递凭据
            config = Config(
                region_id=region_id,
                access_key_id=access_key_id,
                access_key_secret=access_key_secret
            )
        
            # 创建 STS 客户端并获取临时凭证
            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()
        
            # 使用 STS 返回的临时凭据
            sts_accesskeyid = token_data['AccessKeyId']
            sts_accesskeysecret = token_data['AccessKeySecret']
            security_token = token_data['SecurityToken']
        
            now = int(time.time())
        
            # 将时间戳转换为datetime对象
            dt_obj = datetime.datetime.utcfromtimestamp(now)
            # 在当前时间增加3小时,设置为请求的过期时间
            dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
        
            # 请求时间
            dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
            # 请求日期
            dt_obj_2 = dt_obj.strftime('%Y%m%d')
            # 请求过期时间
            expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
        
            # 步骤1:创建policy。
            # 示例policy表单域只列举必填字段,如有其他需求可参考签名版本4文档:https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend
            policy = {
                "expiration": expiration_time,
                "conditions": [
                    {"bucket": "bucket_name"},   #请将<bucket_name>替换为您的实际Bucket名称
                    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
                    {"x-oss-credential": f"{sts_accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},    #请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                    {"x-oss-security-token": security_token},
                    {"x-oss-date": dt_obj_1},
                ]
            }
            policy_str = json.dumps(policy).strip()
        
            # 步骤2:构造待签名字符串(StringToSign)
            stringToSign = base64.b64encode(policy_str.encode()).decode()
        
            # 步骤3:计算SigningKey
            dateKey = hmacsha256(("aliyun_v4" + sts_accesskeysecret).encode(), dt_obj_2)
            dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")    #请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
            dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
            signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
        
            # 步骤4:计算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",    #请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing
                "x_oss_date": dt_obj_1,
                "signature": signature,
                "security_token": security_token
            })
        
        
        if __name__ == "__main__":
            app.run(host='0.0.0.0', port=5000)

      请参考以下示例完成Node.js服务端的V4签名计算。

      • 配置环境变量。

        说明
        • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>请分别替换为RAM用户的AccessKey ID、AccessKeySecret。如何创建AccessKey IDAccessKeySecret请参见创建AccessKey

        • <ROLE_ARN>请替换为目标角色ARN,在角色页面单击目标RAM角色名称,然后在基本信息区域查看对应的ARN。

        • 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>
      • 配置依赖。

        npm install ali-oss
        npm install @alicloud/credentials
        npm install express
      • 代码示例。

        const express = require('express');
        const OSS = require('ali-oss');
        const { STS } = require('ali-oss');
        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; //服务请求端口号
        
        const ECSGenerateSignature = async () => {
            // 初始化STS客户端
            let sts = new STS({
               accessKeyId : process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,  // 从环境变量中获取RAM用户的AccessKey ID
               accessKeySecret : process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET // 从环境变量中获取RAM用户的AccessKey Secret
            
            });
            // 调用assumeRole接口获取STS临时访问凭证
            const result = await sts.assumeRole(process.env.ROLE_ARN, '', '3600', 'sessiontest'); // 从环境变量中获取RAM角色ARN,并设置临时访问凭证有效期为3600秒,角色会话名称为sessiontest可自定义
        
            // 提取临时访问凭证中的AccessKeyId、AccessKeySecret和SecurityToken
            const accessKeyId = result.credentials.AccessKeyId;
            const accessKeySecret = result.credentials.AccessKeySecret;
            const securityToken = result.credentials.SecurityToken;
        
            // 初始化OSS Client
            const client = new OSS({
                bucket: 'bucketname', // 请替换为目标Bucket名称
                region: 'cn-hangzhou', // 请替换为标Bucket所在地域
                accessKeyId,
                accessKeySecret,
                stsToken: securityToken,
                refreshSTSTokenInterval: 0,
                refreshSTSToken: async () => {
                    const { accessKeyId, accessKeySecret, securityToken } = await credentialClient.getCredential();
                    return { accessKeyId, accessKeySecret, stsToken: securityToken };
                },
            });
            
            // 创建表单数据Map
            const formData = new Map();
        
            // 设置签名过期时间为当前时间往后推10分钟 
            const date = new Date();
            const expirationDate = new Date(date);
            expirationDate.setMinutes(date.getMinutes() + 10);
            
            // 格式化日期为符合ISO 8601标准的UTC时间字符串格式
            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);
        
            // 生成x-oss-credential并设置表单数据
            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');
        
            // 创建policy
            // 示例policy表单域只列举必填字段,如有其他需求可参考文档:https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend
            const policy = {
                expiration: expirationDate.toISOString(),
                conditions: [
                    { 'bucket':"bucketname"}, // "bucketname"请替换为目标bucket名称
                    { 'x-oss-credential': credential },
                    { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
                    { 'x-oss-date': formattedDate },
                ],
            };
        
            // 如果存在STS Token,添加到策略和表单数据中
            if (client.options.stsToken) {
                policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
                formData.set('security_token', client.options.stsToken);
            }
        
            // 生成签名并设置表单数据
            const signature = client.signPostObjectPolicyV4(policy, date);
            formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
            formData.set('signature', signature);
        
            // 返回表单数据
            return Object.fromEntries(formData);
        };
        
        app.get('/generate_signature', async (req, res) => {
            try {
                const result = await ECSGenerateSignature();
                res.json(result); // 返回生成的签名数据
            } 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服务端的V4签名计算。

      • 配置环境变量。

        说明
        • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>请分别替换为RAM用户的AccessKey ID、AccessKeySecret。如何创建AccessKey IDAccessKeySecret请参见创建AccessKey

        • <ROLE_ARN>请替换为目标角色ARN,在角色页面单击目标RAM角色名称,然后在基本信息区域查看对应的ARN。

        • 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>
      • 配置依赖。

        go get -u github.com/aliyun/credentials-go
        go mod tidy
      • 代码示例。

        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"
        )
        
        // 定义全局变量
        var (
        	region     string
        	bucketName string
        	product    = "oss"
        )
        
        // PolicyToken 结构体用于存储生成的表单数据 
        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() {
                // 定义默认的IP和端口字符串
        	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 0.0.0.0 8080 ")
        		fmt.Println("")
        		os.Exit(0)
        	}
        	// 打印服务器运行的地址和端口
        	fmt.Printf("server is running on %s \n", strIPPort)
        	// 注册处理根路径请求的函数
        	http.HandleFunc("/", handlerRequest)
        	// 启动HTTP服务器
        	err := http.ListenAndServe(strIPPort, nil)
        	if err != nil {
        		strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
        		panic(strError)
        	}
        }
        
        // handlerRequest 函数处理HTTP请求
        func handlerRequest(w http.ResponseWriter, r *http.Request) {
        	if r.Method == "GET" {
        		response := get_policy_token()
        		w.Header().Set("Access-Control-Allow-Methods", "POST")
        		// 设置允许的源为所有(存在安全风险,生产环境需谨慎使用)
        		w.Header().Set("Access-Control-Allow-Origin", "*")
        		io.WriteString(w, response)
        	}
        }
        
        func get_policy_token() string {
                // 设置bucket所处地域
          	region = "cn-hangzhou"
                // 设置bucket名称
        	bucketName = "bucketName"
        	config := new(credentials.Config).
        		// 填写Credential类型,固定值为ram_role_arn。
        		SetType("ram_role_arn").
        		// 从环境变量中获取RAM用户的访问密钥(AccessKeyId和AccessKeySecret)。
        		SetAccessKeyId(os.Getenv("ALIBABA_ACCESS_KEY_ID")).
        		SetAccessKeySecret(os.Getenv("ALIBABA_ACCESS_KEY_SECRET")).
        		// 从环境变量中获取RAM角色的ARN信息,即需要扮演的角色ID。格式为acs:ram::$accountID:role/$roleName。
        		SetRoleArn(os.Getenv("ROLE_ARN")).
        		// 自定义角色会话名称,用于区分不同的令牌。
        		SetRoleSessionName("Role_Session_Name").
        		// (可选)限制STS Token权限。
        		SetPolicy("").
        		// (可选)限制STS Token的有效时间。
        		SetRoleSessionExpiration(3600)
        
                 // 根据配置创建凭证提供器
        	provider, err := credentials.NewCredential(config)
        	if err != nil {
        		log.Fatalf("NewCredential fail, err:%v", err)
        	}
        
                 // 从凭证提供器获取凭证
        	cred, err := provider.GetCredential()
        	if err != nil {
        		log.Fatalf("GetCredential fail, err:%v", err)
        	}
        	// 构建policy
        	utcTime := time.Now().UTC()
        	date := utcTime.Format("20060102")
        	// 设置签名过期时间为当前时间起一个小时后过期
        	expiration := utcTime.Add(1 * time.Hour)
        	// 示例policy表单域只列举了部分必填字段,如有其他需求可参考文档: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},
        		},
        	}
        
                // 将policy转换为 JSON 格式
        	policy, err := json.Marshal(policyMap)
        	if err != nil {
        		log.Fatalf("json.Marshal fail, err:%v", err)
        	}
        
        	 // 构造待签名字符串(StringToSign)
        	stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
        
        	hmacHash := func() hash.Hash { return sha256.New() }
                 // 构建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)
        
        	// 生成签名
        	h := hmac.New(hmacHash, h4Key)
        	io.WriteString(h, stringToSign)
        	signature := hex.EncodeToString(h.Sum(nil))
        
                // 构建返回给前端的表单
        	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 string(response)
        }

      请参考以下示例完成PHP服务端的V4签名计算。

      • 配置环境变量。

        说明
        • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>请分别替换为RAM用户的AccessKey ID、AccessKeySecret。如何创建AccessKey IDAccessKeySecret请参见创建AccessKey

        • <ROLE_ARN>请替换为目标角色ARN,在角色页面单击目标RAM角色名称,然后在基本信息区域查看对应的ARN。

        • 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>
      • 配置依赖。

        composer require alibabacloud/credentials
      • 代码示例。

        <?php
        require_once 'vendor/autoload.php';
        
        use AlibabaCloud\Credentials\Credential;
        
        // 设置响应头为JSON格式
        header('Content-Type: application/json');
        
        try {
            // 设置bucket所处地域
            $region = 'cn-hangzhou';
            // 设置bucket名称
            $bucket = 'bucketName';
            $product = 'oss';
        
            // 从环境变量获取凭证
            $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('环境变量未正确配置');
            }
        
            // 创建阿里云凭证配置
            $config = new Credential\Config([
                'type' => 'ram_role_arn',
                'accessKeyId' => $accessKeyId,
                'accessKeySecret' => $accessKeySecret,
                'roleArn' => $roleArn,
                'roleSessionName' => 'role_session_name',
                'policy' => '',
                // 设置临时访问凭证过期时间为3600秒
                'roleSessionExpiration' => 3600,
            ]);
        
            // 根据配置创建凭证对象
            $credential = new Credential($config);
            // 从凭证对象中获取凭证信息
            $cred = $credential->getCredential();
        
            // 获取当前的 UTC 时间
            $utcTime = new DateTime('now', new DateTimeZone('UTC'));
            // 格式化当前日期为 Ymd 格式,例如 20240101
            $date = $utcTime->format('Ymd');
            // 克隆当前时间对象,用于设置过期时间
            $expiration = clone $utcTime;
            // 设置过期时间为当前时间往后 1 小时
            $expiration->add(new DateInterval('PT1H'));
            // 构建policy
            // 示例policy表单域只列举了部分必填字段,如有其他需求可参考文档: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()],
                ],
            ];
            // 将policy转换为 JSON 格式的字符串
            $policy = json_encode($policyMap);
            // 对policy字符串进行 Base64 编码,得到待签名的字符串
            $stringToSign = base64_encode($policy);
        
            // 构建signingKey,由固定字符串 "aliyun_v4" 和访问密钥 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);
        
            // 使用 h4Key 对待签名的字符串进行 HMAC-SHA256 签名,得到最终的签名
            $signature = hash_hmac('sha256', $stringToSign, $h4Key);
        
            // 构建响应给前端的表单数据,包含policy、签名版本、凭证、日期、签名和安全令牌等信息
            $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()]);
        }

步骤二:配置微信小程序

  1. 为了确保小程序向OSS发送文件的请求不会被微信拦截,在小程序平台,使用Bucket域名配置微信小程序的合法域名。

    1. 进入Bucket列表,选择目标Bucket后在Bucket内的左侧导航栏,单击概览,然后在访问端口区域复制Bucket名。

      image

    2. 登录微信公众平台,将上传和下载的合法域名填写为Bucket的外网访问域名。如图所示。

      说明

      实际业务中,建议您将OSS提供的外网域名和您自己的域名进行绑定,以便使用自定义域名访问OSS存储空间中的文件。配置步骤,请参见绑定自定义域名

      image

  2. 在微信小程序端,使用从ECS服务端获取到的V4签名凭证信息,发送请求上传文件到OSS。

    说明

    关于上传参数详细说明,请参见签名版本4表单元素

    小程序端上传文件index.js文件示例代码如下,完整示例工程请部署uploadoss.zip

    Page({
      data: {
        key: 'filename.txt',  //待上传的文件名称,您也可以指定其存储在某个目录下。例如,将filename.txt文件上传到youfolder文件夹下,此时需填写:/youfolder/filename.txt。
        policy: '',
        xOssSecurityToken: '',
        xOssSignatureVersion: '',
        xOssCredential: '',
        xOssDate: '',
        xOssSignature: ''
      },
    
      //上传文件方法 
      uploadFileToOSS(filePath, callback) {
        const {
          key,
          policy,
          xOssSecurityToken,
          xOssSignatureVersion,
          xOssCredential,
          xOssDate,
          xOssSignature
        } = this.data;
        
        const apiUrl='http://<ECS实例公网IP地址>:<port>/generate_signature'   //请将IP地址和端口号替换为实际服务器公网IP地址及端口号 
        // 发送请求获取签名信息 
        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;
            
            //此示例上传参数只列举必填字段,如有其他需求可参考:
            //PostObject文档:https://help.aliyun.com/zh/oss/developer-reference/postobject 
            //签名版本4文档:https://help.aliyun.com/zh/oss/developer-reference/signature-version-4-recommend
            const formData = {
              key,  //上传文件名称
              policy: this.data.policy,   //表单域
              'x-oss-signature-version': this.data.xOssSignatureVersion,    //指定签名的版本和算法
              'x-oss-credential': this.data.xOssCredential,   //指明派生密钥的参数集
              'x-oss-date': this.data.xOssDate,   //请求的时间
              'x-oss-signature': this.data.xOssSignature,   //签名认证描述信息
              'x-oss-security-token': this.data.xOssSecurityToken,  //安全令牌
              success_action_status: "200"  //上传成功后响应状态码
            };
    
            // 发送请求上传文件 
            wx.uploadFile({
              url: 'https://examplebucket.oss-cn-hangzhou.aliyuncs.com',  // 此域名仅作示例,实际Bucket域名,请替换为您的目标Bucket域名。
              filePath: filePath,
              name: 'file',   //固定值为file
              formData: formData,
              success(res) {
                console.log('上传响应:', res);
                if (res.statusCode === 200) {
                  callback(null, res.data); // 上传成功
                } else {
                  console.error('上传失败,状态码:', res.statusCode);
                  console.error('失败响应:', res);
                  callback(res); // 上传失败,返回响应
                }
              },
              fail(err) {
                console.error('上传失败:', err); // 输出错误信息
                wx.showToast({ title: '上传失败,请重试!', icon: 'none' });
                callback(err); // 调用回调处理错误
              }
            });
          },
          fail: (err) => {
            console.error('请求接口失败:', err);
            wx.showToast({ title: '获取上传参数失败,请重试!', icon: 'none' });
          }
        });
      },
    
      //点击上传文件按钮触发上传文件代码逻辑  
      chooseAndUploadFile() {
        wx.chooseMessageFile({
          count: 1, // 选择一个文件
          type: 'all', // 支持所有类型的文件
          success: (res) => {
            console.log('选择的文件:', res.tempFiles); // 输出选择的文件信息
            if (res.tempFiles.length > 0) {
              const tempFilePath = res.tempFiles[0].path; // 获取选择的文件路径
              console.log('选择的文件路径:', tempFilePath); // 输出文件路径
              this.uploadFileToOSS(tempFilePath, (error, data) => {
                if (error) {
                  wx.showToast({ title: '上传失败!', icon: 'none' });
                  console.error('上传失败:', error); // 输出具体的错误信息
                } else {
                  wx.showToast({ title: '上传成功!', icon: 'success' });
                  console.log('上传成功:', data); // 输出上传成功后的数据
                }
              });
            } else {
              wx.showToast({ title: '未选择文件!', icon: 'none' });
            }
          },
          fail: (err) => {
            wx.showToast({ title: '选择文件失败!', icon: 'none' });
            console.error('选择文件失败:', err); // 输出选择文件的错误信息
          }
        });
      }
    });

结果验证

  1. 编译运行后,在微信小程序界面单击上传文件

    微信小程序上传文件到OSS.gif

  2. Bucket列表页面,选择上传文件的Bucket并打开,单击右上角任务列表 > 上传列表 您可以在上传列表中看到您通过小程序上传的文件。

    image

  • 本页导读 (1)
  • 方案概览
  • 操作步骤
  • 步骤一:配置服务端
  • 步骤二:配置微信小程序
  • 结果验证
AI助理

点击开启售前

在线咨询服务

你好,我是AI助理

可以解答问题、推荐解决方案等