简介

本文介绍如何不依赖 SDK,用简单的代码,在小程序直传文件到腾讯云COS的存储桶。

注意:

本文档内容基于 XML 版本的 API。

前期条件

  1. 登录 对象存储控制台 ,创建存储桶,设置 BucketName(存储桶名称) 和 Region(地域名称),详情请参见 创建存储桶 文档。
  2. 登录 访问管理控制台,进入 API 密钥管理页面,获取您的项目 SecretId 和 SecretKey。
注意:

目前腾讯云有COS特惠活动,新人1元起

实践步骤

1. 配置小程序域名白名单

小程序里请求腾讯云COS需要登录到微信公众平台,在“开发”->“开发设置”中,配置域名白名单。SDK 用到了两个接口:wx.uploadFile 和 wx.request。

  • cos.postObject 使用 wx.uploadFile 发送请求。
  • 其他方法使用 wx.request 发送请求。

两者都需要在对应白名单里,配置 COS 域名。白名单里配置的域名格式有两种:

  • 如果只用到一个存储桶,可以配置 Bucket 域名作为白名单域名,例如examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com
  • 如果用到多个存储桶,可以选择后缀式请求 COS,把 bucket 放在 pathname 里请求,这种方式需要配置地域域名作为白名单,例如cos.ap-guangzhou.myqcloud.com。具体可参考下文代码中的注释。

2. 获取临时密钥和计算签名

出于安全考虑,签名使用临时密钥,服务端搭建临时密钥服务,请参见 PHP 示例Nodejs 示例
如有其他语言或自行实现可参考以下流程:
(1)向服务端获取临时密钥,服务端首先使用固定密钥 SecretId、SecretKey 向 STS 服务获取临时密钥,得到临时密钥 tmpSecretId、tmpSecretKey、sessionToken,详情请参见 临时密钥生成及使用指引 或 cos-sts-sdk 。

注意:

根据使用的请求是put还是post,STS 的 policy action 要加上允许 "name/cos:PutObject"或"name/cos:PostObject"。

(2)前端通过 tmpSecretId、tmpSecretKey,以及 method、pathname 计算签名,可参考下文使用 cos-auth.js 来计算签名,如果业务需要也可以放在后端计算签名。
(3)将计算得到的签名和 sessionToken,分别放到

  • post请求的formData 的 Signature 和 x-cos-security-token 字段里,向 COS API 发出上传请求。
  • put请求的headers 的 Signature 和 x-cos-security-token 字段里,向 COS API 发出上传请求。
注意:

正式部署时服务端请加一层您的网站本身的权限检验。

3. 后缀式请求

COS API 一般的请求格式都类似POST http://examplebucket-1250000000.cos.ap-beijing.myqcloud.com/,请求的域名是存储桶域名。这样如果在小程序里用到多个存储桶,则需要配置这个存储桶域名作为白名单域名。解决方法如下:

COS 提供了后缀式请求格式POST http://cos.ap-beijing.myqcloud.com/examplebucket-1250000000/,请求的域名是地域域名,存储桶名称放在请求的路径里。在小程序里用到同一个地域多个存储桶,只需要配置一个域名cos.ap-beijing.myqcloud.com作为白名单域名。

后缀式请求格式需要注意,签名时使用的路径要用以存储桶名称作为前缀的路径,例如/examplebucket-1250000000/

4. 直传示例代码

以下代码同时举例了 PUT Object接口(推荐使用)和POST Object接口,操作指引如下:

 
var CosAuth = require('./cos-auth'); // 这里引用了 cos-auth.js,下载地址为 https://unpkg.com/cos-js-sdk-v5/demo/common/cos-auth.min.js 

var Bucket = 'examplebucket-1250000000';
var Region = 'ap-shanghai';
var ForcePathStyle = false; // 是否使用后缀式,涉及签名计算和域名白名单配置,后缀式说明看上文 var uploadFile = function () { // 请求用到的参数
var prefix = 'https://' + Bucket + '.cos.' + Region + '.myqcloud.com/';
if (ForcePathStyle) {
// 后缀式请求在签名时域名使用地域域名,而不是存储桶域名,具体说明见本文上述“3.后缀式请求”
prefix = 'https://cos.' + Region + '.myqcloud.com/' + Bucket + '/';
} // 对更多字符编码的 url encode 格式
var camSafeUrlEncode = function (str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/\*/g, '%2A');
}; // 获取临时密钥
var stsCache;
var getCredentials = function (callback) {
if (stsCache && Date.now() / 1000 + 30 < stsCache.expiredTime) {
callback(data.credentials);
return;
}
wx.request({
method: 'GET',
url: 'https://example.com/sts.php', // 服务端签名,参考上文说的获取临时密钥
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,
})
});
});
}; // post上传文件
var postFile = function (filePath) {
var Key = filePath.substr(filePath.lastIndexOf('/') + 1); // 这里指定上传的文件名
var signPathname = '/'; // PostObject 接口 Key 是放在 Body 传输,所以请求路径和签名路径是 /
if (ForcePathStyle) {
// 后缀式请求在签名时用的路径,要包含存储桶名称,具体说明见本文上述“3.后缀式请求”
signPathname = '/' + Bucket + '/';
}
getAuthorization({Method: 'POST', Pathname: signPathname}, 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(/%2F/g, '/');
console.log(res.statusCode);
console.log(url);
if (/^2\d\d$/.test('' + res.statusCode)) {
wx.showModal({title: '上传成功', content: url, showCancel: false});
} else {
wx.showModal({title: '上传失败', content: JSON.stringify(res), showCancel: false});
}
},
fail: function (res) {
wx.showModal({title: '上传失败', content: JSON.stringify(res), showCancel: false});
}
});
requestTask.onProgressUpdate(function (res) {
console.log('进度:', res);
});
});
}; // put上传文件
var putFile = function (filePath) {
var Key = filePath.substr(filePath.lastIndexOf('/') + 1); // 这里指定上传的文件名
var signPathname = '/' + Key; // PutObject 接口 Key 是放在 url 传输,所以请求路径和签名路径是 /Key
if (ForcePathStyle) {
// 后缀式请求在签名时用的路径,要包含存储桶名称,具体说明见本文上述“3.后缀式请求”
signPathname = '/' + Bucket + '/' + Key;
}
getAuthorization({Method: 'PUT', Pathname: signPathname}, function (AuthData) {
// put请求需要从文件临时路径读取出文件内容
var wxfs = wx.getFileSystemManager();
wxfs.readFile({
filePath: filePath,
success: function (fileRes) {
var requestTask = wx.request({
url: prefix + signPathname.substr(signPathname.lastIndexOf('/') + 1),
method: 'PUT',
header: {
'Authorization': AuthData.Authorization,
'x-cos-security-token': AuthData.XCosSecurityToken,
},
data: fileRes.data,
success: function success(res) {
var url = prefix + camSafeUrlEncode(Key).replace(/%2F/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 fail(res) {
wx.showModal({title: '上传失败', content: JSON.stringify(res), showCancel: false});
},
});
requestTask.onProgressUpdate(function (res) {
console.log('正在进度:', res);
});
},
});
});
}; // 选择文件
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original'], // 可以指定是原图还是压缩图,这里默认用原图
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
putFile(res.tempFiles[0].path); // put请求上传,推荐使用
// postFile(res.tempFiles[0].path); // post请求上传
}
})
};

用简单的代码,将小程序文件直传到腾讯云COS实践的更多相关文章

  1. 微信小程序/网站 上传图片到腾讯云COS

    COS简介: 腾讯云提供的一种对象存储服务,供开发者存储海量文件的分布式存储服务.可以将自己开发的应用的存储部分全部接入COS的存储桶中,有效减少应用服务器的带宽,请求等.个人也可以通过腾讯云账号免费 ...

  2. 微信小程序开发平台新功能「云开发」快速上手体验

    微信小程序开发平台刚刚开放了一个全新的功能:云开发. 简单地说就是将开发人员搭建微信小程序后端的成本再次降低,此文刚好在此产品公测时,来快速上手看看都有哪些方便开发者的功能更新. 微信小程序一直保持一 ...

  3. 微信小程序又一爆炸功能上线-云开发

    云开发介绍 开发者可以使用云开发开发微信小程序.小游戏,无需搭建服务器,即可使用云端能力. 云开发为开发者提供完整的云端支持,弱化后端和运维概念,无需搭建服务器,使用平台提供的 API 进行核心业务开 ...

  4. 微信小程序文件作用域模块引用

    文件作用域 在 JavaScript 文件中声明的变量和函数只在该文件中有效:不同的文件中可以声明相同名字的变量和函数,不会互相影响. 通过全局函数 getApp() 可以获取全局的应用实例,如果需要 ...

  5. 小程序文件上传uploadFile

    前台代码: bindPhoto(e) { var that = this; wx.chooseImage({ count: 1, sizeType: ['original','compressed'] ...

  6. Netty学习——基于netty实现简单的客户端聊天小程序

    Netty学习——基于netty实现简单的客户端聊天小程序 效果图,聊天程序展示 (TCP编程实现) 后端代码: package com.dawa.netty.chatexample; import ...

  7. Winfrom 简单的进度条小程序

    使用Winform空间编写简单的进度条小程序: 所需控件:Lable 标签  TextBox  文本框  progressBar  进度条控件  timer 定时器 下面是源码及效果图: /// &l ...

  8. 【腾讯Bugly干货分享】微信小程序开发思考总结——腾讯“信用卡还款”项目实践

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/58212d0fa7a7574c4f4cc3c5 作者:peggy 小程序概述 1 ...

  9. uniapp之uni-starter小程序多端研发框架搭建与项目实践

    随着移动互联网的飞速发展,无数移动APP琳琅满目:在移动App的发展的基础上,衍生了小程序.轻应用技术,它随时可用,但又无需安装卸载.小程序是一种不需要下载安装即可使用的应用,它实现了应用" ...

  10. uni-app微信小程序开发之引入腾讯视频小程序播放插件

    登录微信小程序管理后台添加腾讯视频播放插件: 正式开始使用腾讯视频小程序插件之前需先在微信公众平台 -> 第三方设置 -> 插件管理处添加插件,如下图所示: 在uni-app中引入插件代码 ...

随机推荐

  1. quasar+vue、Input组件绑定两个值

    项目中关于一个只读input绑定两个值,例如input显示取值范围,通过查看vue及quasar文档找出解决方法,如下代码: <q-input v-bind:value="`${det ...

  2. k8s证书续期10年

    一.拉取脚本 git clone https://github.com/yuyicai/update-kube-cert.git cd update-kube-cert chmod 755 updat ...

  3. java中List的浅拷贝与深拷贝

    List浅拷贝 众所周知,list本质上是数组,而数组的是以地址的形式进行存储. 如上图将list A浅拷贝给list B,由于进行的是浅拷贝,所以直接将A的内容复制给了B,java中相同内容的数组指 ...

  4. TPS,RPS,QPS,RT的区别

    以下是对性能中各项指标的解释:   1.TPS:Transaction Per Second,服务器每秒处理事务数,是衡量系统性能的一个非常重要的指标.   计算公式:TPS= 总请求数 / 总时间. ...

  5. Linux系统Shell脚本第五章:shell数组、正则表达式及文件三剑客之AWK

    目录 一.shell数组 1.数组分类 2.定义数组方法 二.正则表达式 1.元字符 2.表示次数 3.位置锚定 4.分组 5.扩展正则表达式 三.文本三剑客之AWK 1.awk 2.使用格式 3.处 ...

  6. mysql报错This function has none of DETERMINISTIC. NO SOL or READS SOL DATA...

    是因为 存储过程/存储函数在创建时 与 开启慢查询日志冲突了 解决冲突: 临时解决:开启log_bin_trust_function_creators show variables like '%lo ...

  7. 使用Libusb和hidapi测试HID设备

    一.测试中断或者Bulk传输: 首先要使用Libusb打印出HID设备的Endpoint查看是否支持中断或者Bulk传输模式:如果支持的话才可以进一步测试: 因为HID设备在插入的时候无需安装,并且一 ...

  8. python 通过win32com操作vcf到outlook中,同时解决乱码问题

    之前用的黑莓手机,故障后换了iphone,后来还是想用上黑莓Q10.于是有了该文章. 问题: 如何将iphone上的通讯录导入黑莓? 网上回答1:通过icloud将iphone中的通讯录导入黑莓手机. ...

  9. 剑指 Offer 链表

    06. 从尾到头打印链表 class Solution { public: //两个指针一起走 一次翻转一个方向 最后head.next =null ListNode* reverse1(ListNo ...

  10. zookeeper在关闭服务时报could not find file /opt/module/zookeeper-3.5.10/zkData/zookeeper_server.pid

    遇到了个问题,zookeeper在执行 bin/zkServer.sh stop时 会报题目中的错误,我搜了一下博客,好像是因为第一次启动的不是zkServer.sh中的服务 我先 kill -9 加 ...