作者:火种 最近为了实现在小程序上传图片到腾讯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>
运行效果如下: