本文正在参与技术专题征文Node.js进阶之路,点击查看详情
1、注册腾讯云并开通服务
腾讯云 console.cloud.tencent.com/cos
创建存储桶
将访问权限设置为:公有读私有写
创建完成后在桶管理> 安全管理 > 跨域访问CORS设置中添加规则
设置访问管理
访问管理 console.cloud.tencent.com/cam/capi
进入API密钥管理 新建密钥
2、完成STS服务获取临时密钥接口供前端访问 这里采用Node.JS后端实现(Egg.js)
搭建Egg.js项目
略 如果您不了解Egg.js 前往 www.eggjs.org/ 三分钟即可上手写WebAPI
获取临时密钥
获取临时密钥,可以通过提供的 COS STS SDK 方式获取,也可以直接请求 STS 云 API 的方式获取。
这里我们采用SDK方式来获取
安装SDK npm i qcloud-cos-sts --save
在config文件中填写腾讯云配置
// app/config.default.js
// +++
// 腾讯云配置
config.qCloudConfig = {
secretId: 'AKIDhDUVFiwtZ*******aXFgqjMjpfEXZKo', // 固定密钥
secretKey: 'FDuJS********G2Zqrd9QSFm34qM', // 固定密钥
proxy: '',
host: 'cos.ap-shanghai.myqcloud.com', // 域名,非必须,默认为 sts.tencentcloudapi.com
durationSeconds: 1800, // 密钥有效期
// 放行判断相关参数
bucket: 'note-125****098', // 换成你的 bucket
region: 'ap-shanghai', // 换成 bucket 所在地区
allowPrefix: '*', // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
}
// +++
在controller中完成sts逻辑
// app/controller/v1/common.js
'use strict'
const Controller = require('egg').Controller
// 导入SDK
const STS = require('qcloud-cos-sts')
/**
* @Controller 公共模块
*/
class CommonController extends Controller {
/**
* @summary 获取COS Token
* @description 获取腾讯云存储临时访问token
* @router get /api/v1/common/cosToken
*/
async cosToken() {
const { ctx } = this
// 获取配置参数
const { qCloudConfig } = ctx.app.config
// 授权 getCredential
const shortBucketName = qCloudConfig.bucket.substr(0, qCloudConfig.bucket.lastIndexOf('-'));
const appId = qCloudConfig.bucket.substr(1 + qCloudConfig.bucket.lastIndexOf('-'));
const policy = {
version: '2.0',
statement: [{
action: [
// 简单上传
'name/cos:PutObject',
'name/cos:PostObject',
// 分片上传
'name/cos:InitiateMultipartUpload',
'name/cos:ListMultipartUploads',
'name/cos:ListParts',
'name/cos:UploadPart',
'name/cos:CompleteMultipartUpload',
],
effect: 'allow',
principal: { qcs: ['*'] },
resource: [
'qcs::cos:' + qCloudConfig.region + ':uid/' + appId + ':prefix//' + appId + '/' + shortBucketName + '/' + qCloudConfig.allowPrefix,
],
}],
};
try {
const res = await STS.getCredential({
secretId: qCloudConfig.secretId,
secretKey: qCloudConfig.secretKey,
proxy: qCloudConfig.proxy,
durationSeconds: qCloudConfig.durationSeconds,
region: qCloudConfig.region,
policy,
})
console.log(res);
ctx.helper.body.SUCCESS({ ctx, res })
} catch (error) {
console.error(error)
return ctx.helper.body.INVALID_REQUEST({ ctx, code: 500, msg: 'COS授权失败' })
}
}
}
module.exports = CommonController
完成路由配置
// app/router.js
const { router, controller } = app
const { v1 } = controller
// +++
router.get('/api/v1/common/cosToken', v1.common.cosToken)
// +++
访问接口 /api/v1/common/cosToken
3、小程序(uniapp)文件上传
参考腾讯云官方文档 cloud.tencent.com/document/pr…
吐槽官方示例代码 大量callback 回调地狱 /(ㄒoㄒ)/~~
打开uniapp项目
下载依赖
这里引用了 cos-auth.js,下载地址为 unpkg.com/cos-js-sdk-…
下载后放入 src/utils/cos-auth.js
上传代码示例
这里使用了uView 的 Upload 组件
代码实现
<!-- template部分 -->
<view class="file">
<u-upload
:fileList="fileList1"
@afterRead="afterRead"
@delete="deletePic"
name="1"
multiple
:maxCount="9"
:previewFullImage="true"
></u-upload>
</view>
script
import { fetchGetCosToken } from '@/api/note'
// 引入刚刚下载的文件
import CosAuth from '../../utils/cos-auth.min.js'
export default {
data: () => ({
// 文件列表
fileList1: [],
// token
cosToken: {},
}),
onLoad(option) {
// 获取临时token
this.getCosToken()
},
methods: {
// 获取腾讯云token
async getCosToken() {
const { data } = await fetchGetCosToken()
this.cosToken = data
console.log(data)
},
// 对更多字符编码的 url encode 格式
camSafeUrlEncode(str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/\*/g, '%2A')
},
// 计算签名
getAuthorization() {
return {
XCosSecurityToken: this.cosToken.credentials.sessionToken,
Authorization: CosAuth({
SecretId: this.cosToken.credentials.tmpSecretId,
SecretKey: this.cosToken.credentials.tmpSecretKey,
Method: 'POST',
Pathname: '/',
}),
}
},
// 删除图片
deletePic(event) {
this[`fileList${event.name}`].splice(event.index, 1)
},
// 新增图片
async afterRead(event) {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file)
let fileListLen = this[`fileList${event.name}`].length
lists.map((item) => {
this[`fileList${event.name}`].push({
...item,
status: 'uploading',
message: '上传中',
})
})
for (let i = 0; i < lists.length; i++) {
const result = await this.uploadFilePromise(lists[i].thumb)
let item = this[`fileList${event.name}`][fileListLen]
this[`fileList${event.name}`].splice(
fileListLen,
1,
Object.assign(item, {
status: 'success',
message: '',
url: result,
})
)
fileListLen++
}
},
// 上传图片
uploadFilePromise(filePath) {
let Key = filePath.substr(filePath.lastIndexOf('/') + 1)
let signPathname = '/'
console.log(Key)
// 获取签名的token
const AuthData = this.getAuthorization()
let prefix = 'https://note-12594*****.cos.ap-shanghai.myqcloud.com/'
console.log(this.getAuthorization())
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: prefix,
filePath: filePath,
name: 'file',
formData: {
key: Key,
success_action_status: 200,
Signature: AuthData.Authorization,
'x-cos-security-token': AuthData.XCosSecurityToken,
'Content-Type': '',
},
success: (res) => {
console.log(res)
const Encode = this.camSafeUrlEncode(Key)
let url = prefix + Encode.replace(/%2F/g, '/')
console.log(res.statusCode)
console.log(url)
if (/^2\d\d$/.test('' + res.statusCode)) {
console.log(url)
}
resolve(url)
},
fail: (res) => {
console.log(res)
reject(res)
},
})
})
},
}
}
上传文件测试
此时我们上传文件已经可以拿到上传成功后的URL了
接下来需要对uploadFilePromise方法进行封装以便多次复用。