小程序/uniapp使用阿里云serverless进行oss客户端签名直传实践

 最近在弄小程序/uniapp使用阿里云serverless进行oss客户端签名直传,因为官方文档的示例代码瞎几把写看不明白浪费了很多时间摸索,这里记录下:

其实大概半年前用php对接过,也是很不顺利。。。

 node后端代码:

const config = require('../../config');
const OSS = require('ali-oss');


module.exports = class AliOSS {
  static Bucket = 'hejiu-tools';
  static UrlTimeout = 600;

  static getClient() {
    return new OSS({
      accessKeyId: config.oss.RamAK,
      accessKeySecret: config.oss.RamSK,
      region: config.oss.RegionId,
      bucket: AliOSS.Bucket,
      secure: true, // https
    });
  }

  // 小程序端fileUpload只支持post,这个玩意强制put,弃了。
  static async getSignature(fileName) {
    const client = AliOSS.getClient();

    const response = await client.signatureUrlV4(
      'PUT', 60*1000,
      {
        headers: {
          'content-type': 'xxx', // 默认是application/octet-stream,需要换成文件的content-type
        },
      }, fileName
    );

    return response;
  }

    // 表单上传签名,小程序端fileUpload只支持post上传
  static async getPostPolicy() {
    const client = AliOSS.getClient();
    
    const policy = {
      expiration: new Date(Date.now() + 10*60000).toISOString(), // 10分钟后过期
      conditions: [
        ["content-length-range", 0, 104857600] // 文件大小限制100MB
      ]
    };
    
    const formData = client.calculatePostSignature(policy);
    
    return {
      host: `https://${AliOSS.Bucket}.${config.oss.RegionId}.aliyuncs.com`,
      policy: formData.policy,
      signature: formData.Signature,
      OSSAccessKeyId: formData.OSSAccessKeyId,
      expire: Date.now() + 600000
    };
  }

}

 小程序前端代码:

获取签名:

// 因为后端使用了serverless,为了适应http的习惯,所以写了这个类
import MPServerless from '@alicloud/mpserverless-sdk'
import config from '../../../config/config';

export default class Serverless {
    static instance;
    isAuthorized = false;

    constructor(){
        if (!Serverless.instance) {
            this.mpsl = new MPServerless({
                uploadFile: uni.uploadFile,
                request: uni.request,
                getAuthCode: this._getAuthCode,
            }, config.sl); // config.sl: serverless配置
            Serverless.instance = this;
            this._authorize();
        }

        return Serverless.instance;
    }

    _authorize() {
        if (!this.isAuthorized) {
            // 进行匿名授权
            this.mpsl.init({
                authorType: 'anonymous'
            });
            this.isAuthorized = true;
        }
    }

    _getAuthCode(){
        return new Promise(async (resolve, reject) => {
            uni.login({
                provider: 'weixin',
                success: async (res) => {
                    console.log('login success:', res);
                    const authCode = res.code;
                    if(authCode) resolve(authCode);
                    else reject('获取授权码失败');
                },
                fail: (err) => {
                    console.log('login fail:', err);
                }
            })
        })
    }

    request(url='', params={}, loading=false){
        return new Promise(async (resolve, reject) => {
            console.log('SL request:', url, params);
            const [ n, mod, method ]  = url.split('/');
            if(!mod || !method) return reject('Invalid url');

            loading && uni.showLoading({ title: '加载中...' });
            this.mpsl.function.invoke('slapi', { module: mod, method, ...params}).then(res => {
                if(res.success) resolve(res.result);
                reject(res.result);
            }).finally(() => uni.hideLoading());
        });

    }
}

// 获取签名
(new Serverless()).request('/aliCloud/getPostPolicy', {}).then(res => {
				uni.hideLoading();
				console.log(res);
				if(res.code) return uni.showToast({ title: 'OSS服务异常,请稍重试!' });
				this.uploadFile(res.data);
			});

上传文件:

		uploadFile(ossData={}) {
			const { tempFile } = this;
			const fileName = generateUUID()+`.${tempFile.extname}`;
			const filePath = 'dir/'+fileName; // this.$g.tempFile.name
			
			return uni.uploadFile({
				url: config.oss.host,
				name: 'file',
				filePath: tempFile.path,
				formData: Object.assign({key: filePath}, ossData),
				success: (res) => {
					console.log(res);
					if(res?.statusCode >= 300) return this.$g.info('上传失败');
					this.$g.info('上传成功');
					this.path = config.oss.host+`/${filePath}`;
					this.fileName = fileName;
					// this.encodeData(fileName);
				},
				fail: (err) => {
					// console.warn(err);
					this.$g.info('上传失败');
				}
			});
		},

 

posted @ 2025-12-19 22:06  我的五年  阅读(1)  评论(0)    收藏  举报