微信小程序上传图片到腾讯COS存储桶实战

2022-05-26 09:26:03 浏览数 (1)

作者:火种 最近为了实现在小程序上传图片到腾讯COS存储桶,把官方提供的demo,看了一遍又一遍,试了又试,错了又错,踏过一个又一个坑,终于从不懂,到懵懂,到懂。>.<,好累,在此过程就不赘述,直接开始,希望和我一样的小白也可能轻松用上腾讯COS存储桶。

对象存储(Cloud Object Storage,COS)是腾讯云提供的一种存储海量文件的分布式存储服务,用户通过控制台、API、SDK 和工具等多种方式可以简单、快速地接入COS,实现了海量数据存储和管理。如果只是简单地上传图片,不建议使用SDK方式,如果要对存储桶或图片进行操作,建议使用SDK方式。

我用的是前一种,不使用SDK简单地上传图片,实现流程:首先小程序发送请求到中间层安全凭证服务(Security Token Service,STS)获取临时密钥给到前端,接着前端计算签名,然后凭签名再将图片上传到腾讯COS存储桶。(临时密钥有效时间短(30min - 36h),适用于前端直传等临时授权场景,相比永久密钥,安全性更高。)

腾讯提供的STS服务有很多语言,我选了PHP。很方便,只要把sts.php代码中的secretId、secretKey、bucket、region改成自已存储桶的就可以。不过布置PHP服务费了我好长时间,碰到各种情况,归结起来原因就是PHP和运行库版本不一致的问题,最后我选了最新版本的PHP8.1.5和运行库MVC 2015-2022Redistribuable(X64)才布置成功。PHP服务的布置可以参考:

加菲猫注:这里可以用VFP写后端的签名,COS有前端直传和后端上传的两种模式。

https://www.jb51.net/article/120427.htm, PHP服务布置成功后把腾讯提供的sts.php,sts.js, qcloud-sdk-sts.php三个文件放在中间层的根目录wwwroot中,这样STS服务就可以用了。 小程序INDEX.JS的代码如下:

代码语言:javascript复制
var CosAuth = require('../../lib/cos-auth');//cos-auth.js腾讯提供,不用修改。
var config = require('../../config');//config.js腾讯提供,改一下sts.php网址和Bucket和Region就可以。
var prefix = 'https://'   config.Bucket   '.cos.'   config.Region   '.myzijiebao.com/';
var stsCache;
var camSafeUrlEncode=function (str) {
  return encodeURIComponent(str)
      .replace(/!/g, '!')
      .replace(/'/g, ''')
      .replace(/(/g, '(')
      .replace(/)/g, ')')
      .replace(/*/g, '*');
};
// 获取临时密钥
var getCredentials=function (callback) {
  if (stsCache && Date.now() / 1000   30 < stsCache.expiredTime) {
      callback(stsCache.credentials);
      return;
  }
  wx.request({
      method: 'GET',
      url: config.stsUrl, // 服务端签名,
      dataType: 'json',
      success: function (result) {
          var data = result.data;
          var credentials = data.credentials;
          if (credentials) {
              stsCache = data
          } else {
              wx.showModal({title: '临时密钥获取失败', content: JSON.stringify(data), showCancel: false});
          }
          callback(stsCache && stsCache.credentials);
      },
      error: function (err) {
          wx.showModal({title: '临时密钥获取失败', content: JSON.stringify(err), showCancel: false});
      }
  });
};
// 计算签名
var getAuthorization=function (options, callback) {
  getCredentials(function (credentials) {
      callback({
          XCosSecurityToken: credentials.sessionToken,
          Authorization: CosAuth({
              SecretId: credentials.tmpSecretId,
              SecretKey: credentials.tmpSecretKey,
              Method: options.Method,
              Pathname: options.Pathname,
          })
      });
  });
};

Page({
  data: {
   filePath:""
  },

   // 上传文件
  uploadFile:function () {
        var filePath=this.data.filePath;
        //console.log(filePath)
        var Key = filePath.substr(filePath.lastIndexOf('/')   1); // 这里指定上传的文件名
        getAuthorization({Method: 'POST', Pathname: '/'}, function (AuthData) {
            var requestTask = wx.uploadFile({
                url: prefix,
                name: 'file',
                filePath: filePath,
                formData: {
                    'key': Key,
                    'success_action_status': 200,
                    'Signature': AuthData.Authorization,
                    'x-cos-security-token': AuthData.XCosSecurityToken,
                    'Content-Type': '',
                },
                success: function (res) {
                    var url = prefix   camSafeUrlEncode(Key).replace(///g, '/');
                    if (res.statusCode === 200) {
                        wx.showModal({title: '上传成功', content: url, showCancel: false});
                    } else {
                        wx.showModal({title: '上传失败', content: JSON.stringify(res), showCancel: false});
                    }
                    console.log(res.statusCode);
                    console.log(url);
                },
                fail: function (res) {
                    wx.showModal({title: '上传失败', content: JSON.stringify(res), showCancel: false});
                }
            });
            requestTask.onProgressUpdate(function (res) {
                console.log('正在进度:', res);
            });
        });
    },
chooseFile:function() {//打开图库,选择图片
      this.setData({ motto: "选择图片" }),
      wx.chooseImage({
          count: 3,//限制三张图片
          sizeType: ['original', 'compressed'],
          sourceType: ['album', 'camera'],
          success :res => {
          const tempFilePaths = res.tempFilePaths;            this.setData({filePath:tempFilePaths[0]})
          }
      })
  }
})

INDEX.WXML的代码如下:

代码语言:javascript复制
<button bindtap="chooseFile">选择文件</button>
<button bindtap="uploadFile">上传文件</button>
<image style="width: 400px; height: 200px; background-color: #eeeeee;" mode="scaleToFill" src="{{filePath}}"></image>

运行效果如下:

0 人点赞