├── .gitignore ├── LICENSE ├── README.md ├── cors.png ├── demo ├── app.js ├── app.json ├── app.wxss ├── lib │ ├── cos-wx-sdk-v4.js │ └── crypto.js └── pages │ └── index │ ├── config.js │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── dist └── cos-wx-sdk-v4.js ├── gulpfile.js ├── package.json └── src └── qcloud_sdk.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | /samples/album-app 4 | /samples/simple-app/index/config.js -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 腾讯云 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cos-wx-sdk-v4 2 | 3 | ## 已弃用 - 请升级到 cos-wx-sdk-v5 4 | 由于 v4 接口只能上传20MB文件,请直接使用基于 XML API 的 [cos-wx-sdk-v5](https://github.com/tencentyun/cos-wx-sdk-v5)。 5 | 6 | 微信小程序 sdk for [腾讯云对象存储服务](https://www.qcloud.com/product/cos) 7 | 8 | ## 前期准备 9 | 10 | 1. 请您到 https://console.qcloud.com/cos 获取您的项目 ID(appid),bucket,secret_id 和 secret_key。 11 | 3. 请您到 https://console.qcloud.com/cos 针对您要操作的 bucket 进行跨域(CORS)设置,可以按照如下范例,修改来源 Origin: 12 | 13 | ![./cors.png](./cors.png) 14 | 15 | ## 配置 16 | 17 | ### Step1. 下载源码 18 | 从 [github](https://github.com/tencentyun/cos-wx-sdk-v4/archive/master.zip) 下载源码,将 SDK 中 dist 目录下的 [cos-wx-sdk-v4.js](https://github.com/tencentyun/cos-wx-sdk-v4/blob/master/dist/cos-wx-sdk-v4.js) 包含到您的项目中。 19 | 20 | ### Step.2 加载文件 21 | 22 | 把 cos-wx-sdk-v4.js 放在小程序 app/lib/ 目录下,在您的页面 js 里引入: 23 | 24 | ```js 25 | require('../../lib/cos-wx-sdk-v4'); 26 | ``` 27 | 28 | ## 使用 29 | 30 | ### cos-wx-sdk-v4 与 cos-js-sdk-v4 的不同点 31 | 32 | 1. 小程序文件上传过程中,js 没权限读取文件内容,所以 wx-sdk 相比 js-sdk 少了分片上传的所有逻辑。 33 | 2. 由于文件不分片上传只支持 20MB 大小,wx-sdk 上传接口最大只支持 20MB 大小的文件上传。 34 | 3. 小程序里发送请求使用微信提供的 api `wx.request` 和 `wx.uploadFile`。 35 | 36 | ### 示例代码 37 | 38 | 所有的示例代码实现可以参考 samples/simple-app/pages/index/index.js 39 | 40 | ### 初始化 41 | 42 | ```js 43 | //初始化逻辑 44 | //特别注意: WX-SDK 使用之前请先到 https://console.qcloud.com/cos 对相应的Bucket进行跨域设置 45 | var cos = new CosCloud({ 46 | appid: appid, // APPID 必填参数 47 | bucket: bucket, // bucketName 必填参数 48 | region: 'sh', // 地域信息 必填参数 华南地区填 gz 华东填 sh 华北填 tj 49 | getAppSign: function (callback) {//获取签名 必填参数 50 | 51 | // 下面简单讲一下获取签名的几种办法 52 | // 首先,签名的算法具体查看文档:[COS V4 API 签名算法](https://www.qcloud.com/document/product/436/6054) 53 | 54 | // 1.搭建一个鉴权服务器,自己构造请求参数获取签名,推荐实际线上业务使用,优点是安全性好,不会暴露自己的私钥 55 | // 拿到签名之后记得调用callback 56 | /* 57 | wx.request({ 58 | url: 'SIGN_URL', 59 | data: {once: false}, 60 | dataType: 'text', 61 | success: function (result) { 62 | var sig = result.data; 63 | callback(sig); 64 | } 65 | }); 66 | */ 67 | 68 | // 2.直接在浏览器前端计算签名,需要获取自己的 accessKey 和 secretKey, 一般在调试阶段使用 69 | // 拿到签名之后记得调用 callback 70 | // var res = getAuth(false); // 这个函数自己根据签名算法实现 71 | // callback(res); 72 | 73 | // 3.直接复用别人算好的签名字符串, 一般在调试阶段使用 74 | // 拿到签名之后记得调用 callback 75 | // callback('YOUR_SIGN_STR') 76 | 77 | }, 78 | getAppSignOnce: function (callback) { //单次签名,必填参数,参考上面的注释即可 79 | // 填上获取单次签名的逻辑 80 | // var res = getAuth(true); // 这个函数自己根据签名算法实现 81 | // callback(res); 82 | } 83 | }); 84 | ``` 85 | 86 | ## 接口调用示例 87 | 88 | 以下示例代码需要前置定义部分变量 89 | ```js 90 | var bucket = 'WXAPP_BUCKET_NAME'; 91 | var successCallback = function (result) { 92 | console.log('success', result); 93 | } 94 | var errorCallback = function (result) { 95 | console.log('success', result); 96 | } 97 | var progressCallback = function (info) { 98 | console.log('success', result); 99 | } 100 | ``` 101 | 102 | ### 上传程序示例 103 | 104 | ```js 105 | wx.chooseImage({ 106 | count: 1, 107 | sizeType: ['original', 'compressed'], 108 | sourceType: ['album', 'camera'], 109 | success: function (res) { 110 | if (res.tempFilePaths && res.tempFilePaths.length) { 111 | var tempFilePath = res.tempFilePaths[0]; 112 | wx.showToast({title: '正在上传...', icon: 'loading', duration: 60000}); 113 | cos.uploadFile({ 114 | success: successCallback, 115 | error: errorCallback, 116 | onProgress: progressCallback, // 返回 info 对象,带有 loaded、total、percent、speed 四个字段 117 | bucket: 'wx', 118 | path: '/test.png', 119 | filepath: tempFilePath, 120 | insertOnly: 0, // insertOnly==0 表示允许覆盖文件 1表示不允许覆盖 121 | bizAttr: 'test-biz-val' 122 | }); 123 | } 124 | } 125 | }); 126 | ``` 127 | 128 | ### 创建文件夹示例 129 | 130 | ```js 131 | cos.createFolder(successCallback, errorCallback, bucket, '/test', 'folder_first_attr'); 132 | ``` 133 | 134 | ### 获取文件夹内列表示例 135 | 136 | ```js 137 | cos.getFolderList(successCallback, errorCallback, bucket, '/test'); 138 | ``` 139 | 140 | ### 查询文件夹属性示例 141 | 142 | ```js 143 | cos.getFolderStat(successCallback, errorCallback, bucket, '/test'); 144 | ``` 145 | 146 | ### 更新文件夹属性示例 147 | 148 | ```js 149 | cos.updateFolder(successCallback, errorCallback, bucket, '/test', 'folder_new_attr'); 150 | ``` 151 | 152 | ### 删除文件夹示例 153 | 154 | ```js 155 | cos.deleteFolder(successCallback, errorCallback, bucket, '/test'); 156 | ``` 157 | 158 | ### 删除文件示例 159 | ```js 160 | cos.deleteFile(successCallback, errorCallback, bucket, '/test.png'); 161 | ``` 162 | 163 | ### 获取文件属性示例 164 | 165 | ```js 166 | cos.getFileStat(successCallback, errorCallback, bucket, '/test.png'); 167 | ``` 168 | 169 | ### 更新文件属性示例 170 | 171 | ```js 172 | cos.updateFile(successCallback, errorCallback, bucket, '/test.png', 'file_new_attr'); 173 | ``` 174 | 175 | ### 拷贝文件示例 176 | 177 | ```js 178 | cos.copyFile(successCallback, errorCallback, bucket, '/test.png', '/test-cp.png', 0); 179 | ``` 180 | 181 | ### 移动文件示例 182 | 183 | ```js 184 | cos.copyFile(successCallback, errorCallback, bucket, '/test.png', '/test-cp.png', 0); 185 | ``` 186 | 187 | 188 | ## 反馈 189 | 190 | 欢迎提 [issue](https://github.com/tencentyun/cos-wx-sdk-v4/issues) 191 | -------------------------------------------------------------------------------- /cors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tencentyun/cos-wx-sdk-v4/c06cd4e55d2123c01dad4571c0a7247e1ea7d087/cors.png -------------------------------------------------------------------------------- /demo/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | //调用API从本地缓存中获取数据 5 | var logs = wx.getStorageSync('logs') || []; 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | }, 9 | getUserInfo:function(cb){ 10 | var that = this 11 | if(this.globalData.userInfo){ 12 | typeof cb == "function" && cb(this.globalData.userInfo); 13 | }else{ 14 | //调用登录接口 15 | wx.login({ 16 | success: function () { 17 | wx.getUserInfo({ 18 | success: function (res) { 19 | that.globalData.userInfo = res.userInfo; 20 | typeof cb == "function" && cb(that.globalData.userInfo); 21 | } 22 | }) 23 | } 24 | }) 25 | } 26 | }, 27 | globalData:{ 28 | userInfo:null 29 | } 30 | }); -------------------------------------------------------------------------------- /demo/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index" 4 | ], 5 | "window":{ 6 | "backgroundTextStyle":"light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTitleText": "COS 小程序 SDK DEMO", 9 | "navigationBarTextStyle":"black" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /demo/lib/cos-wx-sdk-v4.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* CosCloud */ 4 | function CosCloud(opt) { 5 | this.appid = opt.appid; 6 | this.bucket = opt.bucket; 7 | this.region = opt.region; 8 | this.sign_url = opt.sign_url; 9 | this.progressInterval = opt.progressInterval || 1000; 10 | if (opt.getAppSign) { 11 | this.getAppSign = opt.getAppSign; 12 | } 13 | if (opt.getAppSignOnce) { 14 | this.getAppSignOnce = opt.getAppSignOnce; 15 | } 16 | } 17 | 18 | //512K 19 | var SLICE_SIZE_512K = 524288; 20 | //1M 21 | var SLICE_SIZE_1M = 1048576; 22 | //2M 23 | var SLICE_SIZE_2M = 2097152; 24 | //3M 25 | var SLICE_SIZE_3M = 3145728; 26 | //20M 大于20M的文件需要进行分片传输 27 | var MAX_UNSLICE_FILE_SIZE = 20971520; 28 | 29 | CosCloud.prototype.cosapi_cgi_url = "https://REGION.file.myqcloud.com/files/v2/"; 30 | CosCloud.prototype.sliceSize = 3 * 1024 * 1024; 31 | CosCloud.prototype.getExpired = function (second) { 32 | return parseInt(Date.now() / 1000) + (second || 60); 33 | }; 34 | 35 | 36 | CosCloud.prototype.set = function (opt) { 37 | 38 | if (opt) { 39 | this.appid = opt.appid; 40 | this.bucket = opt.bucket; 41 | this.region = opt.region; 42 | this.sign_url = opt.sign_url; 43 | if (opt.getAppSign) { 44 | this.getAppSign = opt.getAppSign; 45 | } 46 | if (opt.getAppSignOnce) { 47 | this.getAppSignOnce = opt.getAppSignOnce; 48 | } 49 | } 50 | }; 51 | 52 | CosCloud.prototype.getCgiUrl = function (destPath) { 53 | var region = this.region; 54 | var bucket = this.bucket; 55 | var url = this.cosapi_cgi_url; 56 | url = url.replace('REGION', region); 57 | 58 | return url + this.appid + '/' + bucket + '/' + destPath; 59 | 60 | }; 61 | 62 | CosCloud.prototype.updateFolder = function (success, error, bucketName, remotePath, bizAttribute) { 63 | remotePath = fixPath.call(this, remotePath, 'folder'); 64 | this.updateBase(success, error, bucketName, remotePath, bizAttribute); 65 | }; 66 | 67 | CosCloud.prototype.updateFile = function (success, error, bucketName, remotePath, bizAttribute) { 68 | remotePath = fixPath.call(this, remotePath); 69 | this.updateBase(success, error, bucketName, remotePath, bizAttribute); 70 | }; 71 | 72 | CosCloud.prototype.updateBase = function (success, error, bucketName, remotePath, bizAttribute, authority, customHeaders) { 73 | var that = this; 74 | that.getAppSignOnce(function (sign) { 75 | var url = that.getCgiUrl(remotePath); 76 | 77 | var data = { 78 | op: 'update' 79 | }; 80 | 81 | if (bizAttribute) { 82 | data.biz_attr = bizAttribute; 83 | } 84 | //authority 权限类型,可选参数,可选值为eInvalid,eWRPrivate,eWPrivateRPublic 85 | // 文件可以与bucket拥有不同的权限类型,已经设置过权限的文件如果想要撤销,直接赋值为eInvalid,则会采用bucket的权限 86 | if (authority) { 87 | data.authority = authority; 88 | } 89 | 90 | if (customHeaders) { 91 | customHeaders = JSON.stringify(customHeaders); 92 | data.customHeaders = customHeaders; 93 | } 94 | 95 | wx.request({ 96 | method: 'POST', 97 | url: url, 98 | header: {'Authorization': sign}, 99 | data: data, 100 | success: success, 101 | fail: error 102 | }); 103 | }); 104 | }; 105 | 106 | CosCloud.prototype.deleteFolder = function (success, error, bucketName, remotePath) { 107 | remotePath = fixPath.call(this, remotePath, 'folder'); 108 | this.deleteBase(success, error, bucketName, remotePath); 109 | }; 110 | 111 | CosCloud.prototype.deleteFile = function (success, error, bucketName, remotePath) { 112 | remotePath = fixPath.call(this, remotePath); 113 | this.deleteBase(success, error, bucketName, remotePath); 114 | }; 115 | 116 | CosCloud.prototype.deleteBase = function (success, error, bucketName, remotePath) { 117 | if (remotePath == "/") { 118 | error({"code": 10003, "message": "不能删除Bucket"}); 119 | return; 120 | } 121 | var that = this; 122 | this.getAppSignOnce(function (sign) { 123 | var url = that.getCgiUrl(remotePath); 124 | var data = { 125 | op: 'delete' 126 | }; 127 | wx.request({ 128 | method: 'POST', 129 | url: url, 130 | header: {'Authorization': sign}, 131 | data: data, 132 | success: success, 133 | fail: error 134 | }); 135 | }); 136 | }; 137 | 138 | CosCloud.prototype.getFolderStat = function (success, error, bucketName, remotePath) { 139 | remotePath = fixPath(remotePath, 'folder'); 140 | this.statBase(success, error, bucketName, remotePath); 141 | }; 142 | 143 | CosCloud.prototype.getFileStat = function (success, error, bucketName, remotePath) { 144 | remotePath = fixPath(remotePath); 145 | this.statBase(success, error, bucketName, remotePath); 146 | }; 147 | 148 | CosCloud.prototype.statBase = function (success, error, bucketName, remotePath) { 149 | var that = this; 150 | this.getAppSign.call(that, function (sign) { 151 | var url = that.getCgiUrl(remotePath); 152 | var data = { 153 | op: "stat" 154 | }; 155 | wx.request({ 156 | url: url, 157 | method: "GET", 158 | header: {'Authorization': sign}, 159 | data: data, 160 | success: success, 161 | fail: error 162 | }); 163 | }); 164 | 165 | }; 166 | 167 | CosCloud.prototype.createFolder = function (success, error, bucketName, remotePath, bizAttr) { 168 | var that = this; 169 | this.getAppSign(function (sign) { 170 | remotePath = fixPath(remotePath, 'folder'); 171 | var url = that.getCgiUrl(remotePath); 172 | var data = { 173 | op: 'create', 174 | biz_attr: bizAttr || '' 175 | }; 176 | wx.request({ 177 | method: 'POST', 178 | url: url, 179 | header: {'Authorization': sign}, 180 | data: data, 181 | success: success, 182 | fail: error 183 | }); 184 | }); 185 | }; 186 | 187 | CosCloud.prototype.copyFile = function (success, error, bucketName, remotePath, destPath, overWrite) { 188 | var that = this; 189 | this.getAppSign(function (sign) { 190 | remotePath = fixPath(remotePath); 191 | var url = that.getCgiUrl(remotePath); 192 | var data = { 193 | op: 'copy', 194 | dest_fileid: destPath, 195 | to_over_write: overWrite 196 | }; 197 | 198 | wx.request({ 199 | method: 'POST', 200 | url: url, 201 | header: {'Authorization': sign}, 202 | data: data, 203 | success: success, 204 | fail: error 205 | }); 206 | }); 207 | }; 208 | 209 | CosCloud.prototype.moveFile = function (success, error, bucketName, remotePath, destPath, overWrite) { 210 | var that = this; 211 | this.getAppSign(function (sign) { 212 | remotePath = fixPath(remotePath); 213 | var url = that.getCgiUrl(remotePath); 214 | var data = { 215 | op: 'move', 216 | dest_fileid: destPath, 217 | to_over_write: overWrite 218 | }; 219 | 220 | wx.request({ 221 | method: 'POST', 222 | url: url, 223 | header: {'Authorization': sign}, 224 | data: data, 225 | success: success, 226 | fail: error 227 | }); 228 | }); 229 | }; 230 | 231 | CosCloud.prototype.getFolderList = function (success, error, bucketName, remotePath, num, context, order, pattern, prefix) { 232 | var that = this; 233 | 234 | remotePath = fixPath(remotePath, 'folder'); 235 | 236 | that.listBase(success, error, bucketName, remotePath, num, context, order, pattern); 237 | }; 238 | 239 | CosCloud.prototype.listBase = function (success, error, bucketName, remotePath, num, context, order, pattern, prefix) { 240 | var that = this; 241 | that.getAppSign(function (sign) { 242 | var url = that.getCgiUrl(remotePath); 243 | 244 | num = num || 20; 245 | context = context || ''; 246 | order = order || 0; 247 | pattern = pattern || 'eListBoth'; 248 | 249 | var data = { 250 | op: "list", 251 | num: num, 252 | context: context, 253 | order: order, 254 | pattern: pattern 255 | }; 256 | wx.request({ 257 | url: url, 258 | method: "GET", 259 | header: {'Authorization': sign}, 260 | data: data, 261 | success: success, 262 | fail: error 263 | }); 264 | }); 265 | }; 266 | 267 | CosCloud.prototype.uploadFile = function (success, error, bucketName, remotePath, tempFilePath, insertOnly) { 268 | 269 | var options = {}; 270 | var bizAttr = {}; 271 | var onProgress; 272 | if (typeof success === 'object') { 273 | options = success; 274 | bizAttr = options.bizAttr; 275 | success = options.success; 276 | error = options.error; 277 | bucketName = options.bucket; 278 | remotePath = options.path; 279 | tempFilePath = options.filepath; 280 | insertOnly = options.insertOnly; 281 | if (options.onProgress && (typeof options.onProgress === 'function')) { 282 | onProgress = (function () { 283 | var time0 = Date.now(); 284 | var size0 = 0; 285 | var FinishSize = 0; 286 | var FileSize = 0; 287 | var progressTimer; 288 | var update = function () { 289 | progressTimer = 0; 290 | var time1 = Date.now(); 291 | var speed = parseInt((FinishSize - size0) / ((time1 - time0) / 1000) * 100) / 100 || 0; 292 | var percent = parseInt(FinishSize / FileSize * 100) / 100 || 0; 293 | time0 = time1; 294 | size0 = FinishSize; 295 | try { 296 | options.onProgress({ 297 | loaded: FinishSize, 298 | total: FileSize, 299 | speed: speed, 300 | percent: percent 301 | }); 302 | } catch (e) { 303 | } 304 | }; 305 | return function (info, immediately) { 306 | if (info) { 307 | FinishSize = info.totalBytesSent; 308 | FileSize = info.totalBytesExpectedToSend; 309 | } 310 | if (immediately) { 311 | if (progressTimer) { 312 | clearTimeout(progressTimer); 313 | update(); 314 | } 315 | } else { 316 | if (progressTimer) return; 317 | progressTimer = setTimeout(update, that.progressInterval || 1000); 318 | } 319 | }; 320 | })(); 321 | } 322 | } 323 | 324 | var that = this; 325 | remotePath = fixPath(remotePath); 326 | that.getAppSign(function (sign) { 327 | var url = that.getCgiUrl(remotePath); 328 | var data = { 329 | op: 'upload' 330 | }; 331 | if (insertOnly >= 0) {//insertOnly==0 表示允许覆盖文件 1表示不允许 其他值忽略 332 | data['insertOnly'] = insertOnly; 333 | } 334 | if (bizAttr) { 335 | data['biz_attr'] = bizAttr; 336 | } 337 | var uploadTask = wx.uploadFile({ 338 | url: url, 339 | filePath: tempFilePath, 340 | name: 'fileContent', 341 | header: {'Authorization': sign}, 342 | formData: data, 343 | success: function (result) { 344 | result.data = JSON.parse(result.data); 345 | onProgress(null, true); 346 | success.call(this, result); 347 | }, 348 | fail: error 349 | }); 350 | onProgress && uploadTask && uploadTask.onProgressUpdate && uploadTask.onProgressUpdate(onProgress); 351 | }); 352 | }; 353 | 354 | //处理路径 355 | function fixPath(path, type) { 356 | 357 | if (!path) { 358 | return ''; 359 | } 360 | var self = this; 361 | path = path.replace(/(^\/*)|(\/*$)/g, ''); 362 | if (type == 'folder') { 363 | path = encodeURIComponent(path + '/').replace(/%2F/g, '/'); 364 | } else { 365 | path = encodeURIComponent(path).replace(/%2F/g, '/'); 366 | } 367 | 368 | if (self) { 369 | self.path = '/' + self.appid + '/' + self.bucket + '/' + path; 370 | } 371 | 372 | return path; 373 | } 374 | 375 | module.exports = CosCloud; -------------------------------------------------------------------------------- /demo/lib/crypto.js: -------------------------------------------------------------------------------- 1 | /* 2 | CryptoJS v3.1.2 3 | code.google.com/p/crypto-js 4 | (c) 2009-2013 by Jeff Mott. All rights reserved. 5 | code.google.com/p/crypto-js/wiki/License 6 | */ 7 | var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, 8 | p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< 9 | 32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>3]|=parseInt(a.substr(f, 10 | 2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}}, 11 | r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;ka;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^ 15 | g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})(); 16 | (function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h>> 2] >>> (24 - (i % 4) * 8)) & 0xff; 57 | var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; 58 | var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; 59 | 60 | var triplet = (byte1 << 16) | (byte2 << 8) | byte3; 61 | 62 | for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { 63 | base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); 64 | } 65 | } 66 | 67 | // Add padding 68 | var paddingChar = map.charAt(64); 69 | if (paddingChar) { 70 | while (base64Chars.length % 4) { 71 | base64Chars.push(paddingChar); 72 | } 73 | } 74 | 75 | return base64Chars.join(''); 76 | }, 77 | 78 | /** 79 | * Converts a Base64 string to a word array. 80 | * 81 | * @param {string} base64Str The Base64 string. 82 | * 83 | * @return {WordArray} The word array. 84 | * 85 | * @static 86 | * 87 | * @example 88 | * 89 | * var wordArray = CryptoJS.enc.Base64.parse(base64String); 90 | */ 91 | parse: function (base64Str) { 92 | // Shortcuts 93 | var base64StrLength = base64Str.length; 94 | var map = this._map; 95 | 96 | // Ignore padding 97 | var paddingChar = map.charAt(64); 98 | if (paddingChar) { 99 | var paddingIndex = base64Str.indexOf(paddingChar); 100 | if (paddingIndex != -1) { 101 | base64StrLength = paddingIndex; 102 | } 103 | } 104 | 105 | // Convert 106 | var words = []; 107 | var nBytes = 0; 108 | for (var i = 0; i < base64StrLength; i++) { 109 | if (i % 4) { 110 | var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); 111 | var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); 112 | words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); 113 | nBytes++; 114 | } 115 | } 116 | 117 | return WordArray.create(words, nBytes); 118 | }, 119 | 120 | _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' 121 | }; 122 | }()); 123 | 124 | if(typeof module === 'object'){ 125 | module.exports = CryptoJS; 126 | }else{ 127 | window.CryptoJS = CryptoJS; 128 | } 129 | -------------------------------------------------------------------------------- /demo/pages/index/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | appid: '', // Bucket 所属的项目 ID 3 | bucket: '', // 空间名称 Bucket 4 | region: '', // bucket 的地域简称,华南:gz,华北:tj,华东:sh 5 | sid: '', // 项目的 SecretID 6 | skey: '' // 项目的 Secret Key 7 | }; -------------------------------------------------------------------------------- /demo/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | 3 | var CosCloud = require('../../lib/cos-wx-sdk-v4'); 4 | var CryptoJS = require('../../lib/crypto'); 5 | var config = require('./config'); 6 | 7 | var appid = config.appid; 8 | var bucket = config.bucket; 9 | var region = config.region; 10 | var sid = config.sid; 11 | var skey = config.skey; 12 | var getSignature = function (once) { 13 | var that = this; 14 | var random = parseInt(Math.random() * Math.pow(2, 32)); 15 | var now = parseInt(new Date().getTime() / 1000); 16 | var e = now + 60; //签名过期时间为当前+60s 17 | var path = ''; //多次签名这里填空 18 | var str = 'a=' + appid + '&k=' + sid + '&e=' + e + '&t=' + now + '&r=' + random + 19 | '&f=' + path + '&b=' + bucket; 20 | var sha1Res = CryptoJS.HmacSHA1(str, skey);//这里使用CryptoJS计算sha1值,你也可以用其他开源库或自己实现 21 | var strWordArray = CryptoJS.enc.Utf8.parse(str); 22 | var resWordArray = sha1Res.concat(strWordArray); 23 | var res = resWordArray.toString(CryptoJS.enc.Base64); 24 | return res; 25 | }; 26 | 27 | var cos = new CosCloud({ 28 | appid: appid, // APPID 必填参数 29 | bucket: bucket, // bucketName 必填参数 30 | region: region, // 地域信息 必填参数 华南地区填gz 华东填sh 华北填tj 31 | progressInterval: 1000, // 控制上传进度回调间隔 32 | getAppSign: function (callback) {//获取签名 必填参数 33 | 34 | // 下面简单讲一下获取签名的几种办法 35 | // 首先,签名的算法具体查看文档:[COS V4 API 签名算法](https://www.qcloud.com/document/product/436/6054) 36 | 37 | // 1.搭建一个鉴权服务器,自己构造请求参数获取签名,推荐实际线上业务使用,优点是安全性好,不会暴露自己的私钥 38 | // 拿到签名之后记得调用callback 39 | /* 40 | wx.request({ 41 | url: 'SIGN_URL', 42 | data: {once: false}, 43 | dataType: 'text', 44 | success: function (result) { 45 | var sig = result.data; 46 | callback(sig); 47 | } 48 | }); 49 | */ 50 | 51 | // 2.直接在浏览器前端计算签名,需要获取自己的 accessKey 和 secretKey, 一般在调试阶段使用 52 | // 拿到签名之后记得调用 callback 53 | var res = getSignature(false); // 这个函数自己根据签名算法实现 54 | callback(res); 55 | 56 | // 3.直接复用别人算好的签名字符串, 一般在调试阶段使用 57 | // 拿到签名之后记得调用 callback 58 | // callback('YOUR_SIGN_STR') 59 | 60 | }, 61 | getAppSignOnce: function (callback) { //单次签名,必填参数,参考上面的注释即可 62 | // 填上获取单次签名的逻辑 63 | var res = getSignature(true); // 这个函数自己根据签名算法实现 64 | callback(res); 65 | } 66 | }); 67 | 68 | var ERR = { 69 | // 其他错误码查看文档:https://www.qcloud.com/document/product/436/6059 70 | 'ERROR_CMD_COS_PATH_CONFLICT': '文件/目录已存在', 71 | 'ERROR_CMD_FILE_NOTEXIST': '文件/目录不存在', 72 | 'ERROR_SAME_FILE_UPLOAD': '不能覆盖已存在文件' 73 | }; 74 | 75 | //获取应用实例 76 | Page({ 77 | // 回调统一处理函数 78 | createCallBack: function (msg) { 79 | var that = this; 80 | return function (result) { 81 | console.log(result); 82 | that.loading(0); 83 | if (result.errMsg != 'request:ok' && result.errMsg != 'uploadFile:ok') { 84 | wx.showModal({title: '请求出错', content: '请求出错:' + result.errMsg + ';状态码:' + result.statusCode, 85 | showCancel: false}); 86 | } else if (result.data.code) { 87 | wx.showModal({title: '返回错误', 88 | content: (msg || '请求') + '失败:' + (ERR[result.data.message] || result.data.message) + 89 | ';状态码:' + result.statusCode, showCancel: false}); 90 | } else { 91 | wx.showToast({title: (msg || '请求') + '成功', icon: 'success', duration: 3000}); 92 | } 93 | } 94 | }, 95 | // 回调统一处理函数 96 | loading: function (isLoading, msg) { 97 | if (isLoading) { 98 | wx.showToast({title: (msg || '正在请求...'), icon: 'loading', duration: 60000}); 99 | } else { 100 | wx.hideToast(); 101 | } 102 | }, 103 | // 创建目录 104 | createFolder: function () { 105 | cos.createFolder(this.createCallBack('1. /test 目录创建'), this.createCallBack(), bucket, '/test', 'folder_first_attr'); // 最后的 bizAttr 参数可省略 106 | }, 107 | // 列出目录 108 | getFolderList: function () { 109 | cos.getFolderList(this.createCallBack('2. /test 目录列出'), this.createCallBack(), bucket, '/test'); 110 | }, 111 | // 查询目录属性 112 | getFolderStat: function () { 113 | cos.getFolderStat(this.createCallBack('3. /test 目录属性查询'), this.createCallBack(), bucket, '/test'); 114 | }, 115 | // 更新目录属性 116 | updateFolder: function () { 117 | cos.updateFolder(this.createCallBack('4. /test 目录属性更新'), this.createCallBack(), bucket, '/test', 'folder_new_attr'); 118 | }, 119 | // 删除目录 120 | deleteFolder: function () { 121 | cos.deleteFolder(this.createCallBack('5. /test 目录删除'), this.createCallBack(), bucket, '/test'); 122 | }, 123 | // 简单上传文件 124 | uploadFile: function () { 125 | var that = this; 126 | wx.chooseImage({ 127 | count: 1, 128 | sizeType: ['original', 'compressed'], 129 | sourceType: ['album', 'camera'], 130 | success: function (res) { 131 | if (res.tempFilePaths && res.tempFilePaths.length) { 132 | var tempFilePath = res.tempFilePaths[0]; 133 | that.loading(1, '正在上传...'); 134 | cos.uploadFile({ 135 | success: that.createCallBack('6. /test.png 文件上传'), 136 | error: that.createCallBack(), 137 | bucket: bucket, 138 | path: '/test.png', 139 | filepath: tempFilePath, 140 | insertOnly: 0, // insertOnly==0 表示允许覆盖文件 1表示不允许覆盖 141 | bizAttr: 'test-biz-val', 142 | onProgress: function (info) { 143 | console.log(info); 144 | } 145 | }); 146 | } 147 | } 148 | }); 149 | }, 150 | // 查询文件属性 151 | getFileStat: function () { 152 | cos.getFileStat(this.createCallBack('7. /test.png 文件属性查询'), this.createCallBack(), bucket, '/test.png'); 153 | }, 154 | // 更新文件属性 155 | updateFile: function () { 156 | cos.updateFile(this.createCallBack('8. /test.png 文件属性更新'), this.createCallBack(), bucket, '/test.png', 'file_new_attr'); 157 | }, 158 | // 删除文件 159 | deleteFile: function () { 160 | cos.deleteFile(this.createCallBack('9. /test.png 文件删除'), this.createCallBack(), bucket, '/test.png'); 161 | }, 162 | // 复制文件 163 | copyFile: function () { 164 | cos.copyFile(this.createCallBack('10. /test.png 文件复制'), this.createCallBack(), bucket, '/test.png', '/test-cp.png', 0); // overWrite==0 表示不允许覆盖文件 1表示允许覆盖 165 | }, 166 | // 移动文件 167 | moveFile: function () { 168 | cos.moveFile(this.createCallBack('11. /test.png 文件移动'), this.createCallBack(), bucket, '/test.png', '/test-mv.png', 0); // overWrite==0 表示不允许覆盖文件 1表示允许覆盖 169 | } 170 | }); 171 | -------------------------------------------------------------------------------- /demo/pages/index/index.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /demo/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 接口调用例子 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | .userinfo { 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | } 7 | 8 | .userinfo-nickname { 9 | color: #aaa; 10 | } 11 | 12 | .user-motto { 13 | margin:auto; 14 | font-size:14px; 15 | color:#999; 16 | display:block; 17 | line-height:32px; 18 | } 19 | 20 | .user-button { 21 | margin-top: 3px; 22 | text-align: left; 23 | height:36px; 24 | line-height:36px; 25 | padding:0 10px; 26 | } -------------------------------------------------------------------------------- /dist/cos-wx-sdk-v4.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* CosCloud */ 4 | function CosCloud(opt) { 5 | this.appid = opt.appid; 6 | this.bucket = opt.bucket; 7 | this.region = opt.region; 8 | this.sign_url = opt.sign_url; 9 | this.progressInterval = opt.progressInterval || 1000; 10 | if (opt.getAppSign) { 11 | this.getAppSign = opt.getAppSign; 12 | } 13 | if (opt.getAppSignOnce) { 14 | this.getAppSignOnce = opt.getAppSignOnce; 15 | } 16 | } 17 | 18 | //512K 19 | var SLICE_SIZE_512K = 524288; 20 | //1M 21 | var SLICE_SIZE_1M = 1048576; 22 | //2M 23 | var SLICE_SIZE_2M = 2097152; 24 | //3M 25 | var SLICE_SIZE_3M = 3145728; 26 | //20M 大于20M的文件需要进行分片传输 27 | var MAX_UNSLICE_FILE_SIZE = 20971520; 28 | 29 | CosCloud.prototype.cosapi_cgi_url = "https://REGION.file.myqcloud.com/files/v2/"; 30 | CosCloud.prototype.sliceSize = 3 * 1024 * 1024; 31 | CosCloud.prototype.getExpired = function (second) { 32 | return parseInt(Date.now() / 1000) + (second || 60); 33 | }; 34 | 35 | 36 | CosCloud.prototype.set = function (opt) { 37 | 38 | if (opt) { 39 | this.appid = opt.appid; 40 | this.bucket = opt.bucket; 41 | this.region = opt.region; 42 | this.sign_url = opt.sign_url; 43 | if (opt.getAppSign) { 44 | this.getAppSign = opt.getAppSign; 45 | } 46 | if (opt.getAppSignOnce) { 47 | this.getAppSignOnce = opt.getAppSignOnce; 48 | } 49 | } 50 | }; 51 | 52 | CosCloud.prototype.getCgiUrl = function (destPath) { 53 | var region = this.region; 54 | var bucket = this.bucket; 55 | var url = this.cosapi_cgi_url; 56 | url = url.replace('REGION', region); 57 | 58 | return url + this.appid + '/' + bucket + '/' + destPath; 59 | 60 | }; 61 | 62 | CosCloud.prototype.updateFolder = function (success, error, bucketName, remotePath, bizAttribute) { 63 | remotePath = fixPath.call(this, remotePath, 'folder'); 64 | this.updateBase(success, error, bucketName, remotePath, bizAttribute); 65 | }; 66 | 67 | CosCloud.prototype.updateFile = function (success, error, bucketName, remotePath, bizAttribute) { 68 | remotePath = fixPath.call(this, remotePath); 69 | this.updateBase(success, error, bucketName, remotePath, bizAttribute); 70 | }; 71 | 72 | CosCloud.prototype.updateBase = function (success, error, bucketName, remotePath, bizAttribute, authority, customHeaders) { 73 | var that = this; 74 | that.getAppSignOnce(function (sign) { 75 | var url = that.getCgiUrl(remotePath); 76 | 77 | var data = { 78 | op: 'update' 79 | }; 80 | 81 | if (bizAttribute) { 82 | data.biz_attr = bizAttribute; 83 | } 84 | //authority 权限类型,可选参数,可选值为eInvalid,eWRPrivate,eWPrivateRPublic 85 | // 文件可以与bucket拥有不同的权限类型,已经设置过权限的文件如果想要撤销,直接赋值为eInvalid,则会采用bucket的权限 86 | if (authority) { 87 | data.authority = authority; 88 | } 89 | 90 | if (customHeaders) { 91 | customHeaders = JSON.stringify(customHeaders); 92 | data.customHeaders = customHeaders; 93 | } 94 | 95 | wx.request({ 96 | method: 'POST', 97 | url: url, 98 | header: {'Authorization': sign}, 99 | data: data, 100 | success: success, 101 | fail: error 102 | }); 103 | }); 104 | }; 105 | 106 | CosCloud.prototype.deleteFolder = function (success, error, bucketName, remotePath) { 107 | remotePath = fixPath.call(this, remotePath, 'folder'); 108 | this.deleteBase(success, error, bucketName, remotePath); 109 | }; 110 | 111 | CosCloud.prototype.deleteFile = function (success, error, bucketName, remotePath) { 112 | remotePath = fixPath.call(this, remotePath); 113 | this.deleteBase(success, error, bucketName, remotePath); 114 | }; 115 | 116 | CosCloud.prototype.deleteBase = function (success, error, bucketName, remotePath) { 117 | if (remotePath == "/") { 118 | error({"code": 10003, "message": "不能删除Bucket"}); 119 | return; 120 | } 121 | var that = this; 122 | this.getAppSignOnce(function (sign) { 123 | var url = that.getCgiUrl(remotePath); 124 | var data = { 125 | op: 'delete' 126 | }; 127 | wx.request({ 128 | method: 'POST', 129 | url: url, 130 | header: {'Authorization': sign}, 131 | data: data, 132 | success: success, 133 | fail: error 134 | }); 135 | }); 136 | }; 137 | 138 | CosCloud.prototype.getFolderStat = function (success, error, bucketName, remotePath) { 139 | remotePath = fixPath(remotePath, 'folder'); 140 | this.statBase(success, error, bucketName, remotePath); 141 | }; 142 | 143 | CosCloud.prototype.getFileStat = function (success, error, bucketName, remotePath) { 144 | remotePath = fixPath(remotePath); 145 | this.statBase(success, error, bucketName, remotePath); 146 | }; 147 | 148 | CosCloud.prototype.statBase = function (success, error, bucketName, remotePath) { 149 | var that = this; 150 | this.getAppSign.call(that, function (sign) { 151 | var url = that.getCgiUrl(remotePath); 152 | var data = { 153 | op: "stat" 154 | }; 155 | wx.request({ 156 | url: url, 157 | method: "GET", 158 | header: {'Authorization': sign}, 159 | data: data, 160 | success: success, 161 | fail: error 162 | }); 163 | }); 164 | 165 | }; 166 | 167 | CosCloud.prototype.createFolder = function (success, error, bucketName, remotePath, bizAttr) { 168 | var that = this; 169 | this.getAppSign(function (sign) { 170 | remotePath = fixPath(remotePath, 'folder'); 171 | var url = that.getCgiUrl(remotePath); 172 | var data = { 173 | op: 'create', 174 | biz_attr: bizAttr || '' 175 | }; 176 | wx.request({ 177 | method: 'POST', 178 | url: url, 179 | header: {'Authorization': sign}, 180 | data: data, 181 | success: success, 182 | fail: error 183 | }); 184 | }); 185 | }; 186 | 187 | CosCloud.prototype.copyFile = function (success, error, bucketName, remotePath, destPath, overWrite) { 188 | var that = this; 189 | this.getAppSign(function (sign) { 190 | remotePath = fixPath(remotePath); 191 | var url = that.getCgiUrl(remotePath); 192 | var data = { 193 | op: 'copy', 194 | dest_fileid: destPath, 195 | to_over_write: overWrite 196 | }; 197 | 198 | wx.request({ 199 | method: 'POST', 200 | url: url, 201 | header: {'Authorization': sign}, 202 | data: data, 203 | success: success, 204 | fail: error 205 | }); 206 | }); 207 | }; 208 | 209 | CosCloud.prototype.moveFile = function (success, error, bucketName, remotePath, destPath, overWrite) { 210 | var that = this; 211 | this.getAppSign(function (sign) { 212 | remotePath = fixPath(remotePath); 213 | var url = that.getCgiUrl(remotePath); 214 | var data = { 215 | op: 'move', 216 | dest_fileid: destPath, 217 | to_over_write: overWrite 218 | }; 219 | 220 | wx.request({ 221 | method: 'POST', 222 | url: url, 223 | header: {'Authorization': sign}, 224 | data: data, 225 | success: success, 226 | fail: error 227 | }); 228 | }); 229 | }; 230 | 231 | CosCloud.prototype.getFolderList = function (success, error, bucketName, remotePath, num, context, order, pattern, prefix) { 232 | var that = this; 233 | 234 | remotePath = fixPath(remotePath, 'folder'); 235 | 236 | that.listBase(success, error, bucketName, remotePath, num, context, order, pattern); 237 | }; 238 | 239 | CosCloud.prototype.listBase = function (success, error, bucketName, remotePath, num, context, order, pattern, prefix) { 240 | var that = this; 241 | that.getAppSign(function (sign) { 242 | var url = that.getCgiUrl(remotePath); 243 | 244 | num = num || 20; 245 | context = context || ''; 246 | order = order || 0; 247 | pattern = pattern || 'eListBoth'; 248 | 249 | var data = { 250 | op: "list", 251 | num: num, 252 | context: context, 253 | order: order, 254 | pattern: pattern 255 | }; 256 | wx.request({ 257 | url: url, 258 | method: "GET", 259 | header: {'Authorization': sign}, 260 | data: data, 261 | success: success, 262 | fail: error 263 | }); 264 | }); 265 | }; 266 | 267 | CosCloud.prototype.uploadFile = function (success, error, bucketName, remotePath, tempFilePath, insertOnly) { 268 | 269 | var options = {}; 270 | var bizAttr = {}; 271 | var onProgress; 272 | if (typeof success === 'object') { 273 | options = success; 274 | bizAttr = options.bizAttr; 275 | success = options.success; 276 | error = options.error; 277 | bucketName = options.bucket; 278 | remotePath = options.path; 279 | tempFilePath = options.filepath; 280 | insertOnly = options.insertOnly; 281 | if (options.onProgress && (typeof options.onProgress === 'function')) { 282 | onProgress = (function () { 283 | var time0 = Date.now(); 284 | var size0 = 0; 285 | var FinishSize = 0; 286 | var FileSize = 0; 287 | var progressTimer; 288 | var update = function () { 289 | progressTimer = 0; 290 | var time1 = Date.now(); 291 | var speed = parseInt((FinishSize - size0) / ((time1 - time0) / 1000) * 100) / 100 || 0; 292 | var percent = parseInt(FinishSize / FileSize * 100) / 100 || 0; 293 | time0 = time1; 294 | size0 = FinishSize; 295 | try { 296 | options.onProgress({ 297 | loaded: FinishSize, 298 | total: FileSize, 299 | speed: speed, 300 | percent: percent 301 | }); 302 | } catch (e) { 303 | } 304 | }; 305 | return function (info, immediately) { 306 | if (info) { 307 | FinishSize = info.totalBytesSent; 308 | FileSize = info.totalBytesExpectedToSend; 309 | } 310 | if (immediately) { 311 | if (progressTimer) { 312 | clearTimeout(progressTimer); 313 | update(); 314 | } 315 | } else { 316 | if (progressTimer) return; 317 | progressTimer = setTimeout(update, that.progressInterval || 1000); 318 | } 319 | }; 320 | })(); 321 | } 322 | } 323 | 324 | var that = this; 325 | remotePath = fixPath(remotePath); 326 | that.getAppSign(function (sign) { 327 | var url = that.getCgiUrl(remotePath); 328 | var data = { 329 | op: 'upload' 330 | }; 331 | if (insertOnly >= 0) {//insertOnly==0 表示允许覆盖文件 1表示不允许 其他值忽略 332 | data['insertOnly'] = insertOnly; 333 | } 334 | if (bizAttr) { 335 | data['biz_attr'] = bizAttr; 336 | } 337 | var uploadTask = wx.uploadFile({ 338 | url: url, 339 | filePath: tempFilePath, 340 | name: 'fileContent', 341 | header: {'Authorization': sign}, 342 | formData: data, 343 | success: function (result) { 344 | result.data = JSON.parse(result.data); 345 | onProgress(null, true); 346 | success.call(this, result); 347 | }, 348 | fail: error 349 | }); 350 | onProgress && uploadTask && uploadTask.onProgressUpdate && uploadTask.onProgressUpdate(onProgress); 351 | }); 352 | }; 353 | 354 | //处理路径 355 | function fixPath(path, type) { 356 | 357 | if (!path) { 358 | return ''; 359 | } 360 | var self = this; 361 | path = path.replace(/(^\/*)|(\/*$)/g, ''); 362 | if (type == 'folder') { 363 | path = encodeURIComponent(path + '/').replace(/%2F/g, '/'); 364 | } else { 365 | path = encodeURIComponent(path).replace(/%2F/g, '/'); 366 | } 367 | 368 | if (self) { 369 | self.path = '/' + self.appid + '/' + self.bucket + '/' + path; 370 | } 371 | 372 | return path; 373 | } 374 | 375 | module.exports = CosCloud; -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /* global require */ 2 | var gulp = require('gulp'); 3 | var gulpLoadPlugins = require('gulp-load-plugins'); 4 | var plugins = gulpLoadPlugins(); 5 | var uglify = require('gulp-uglify'); 6 | 7 | gulp.task('default', ['rjs']); 8 | 9 | 10 | var concatTask = function () { 11 | gulp.src(["./src/*.js"]) 12 | .pipe(uglify({preserveComments: 'license'})) 13 | .pipe(plugins.concat("cos-wx-sdk-v4.js")) 14 | .pipe(gulp.dest("./demo/lib/")) // 这是 demo 需要引用的文件 15 | .pipe(gulp.dest("./dist/").on('finish', function () { 16 | console.log('concat done...'); 17 | })); 18 | }; 19 | 20 | gulp.task('rjs', function () { 21 | concatTask(); 22 | // 文件合并 23 | gulp.watch("../src/*.js", function (event) { 24 | concatTask(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cos-wx-sdk-v4", 3 | "version": "1.0.1", 4 | "description": "wx-sdk-v4 for [腾讯云对象存储服务](http://wiki.qcloud.com/wiki/COS%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D)", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "gulp" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "http://git.code.oa.com/cdn/cos-wx-sdk-v4.git" 12 | }, 13 | "devDependencies": { 14 | "gulp": "^3.8.11", 15 | "gulp-concat": "^2.5.2", 16 | "gulp-load-plugins": "^0.10.0", 17 | "gulp-uglify": "^1.5.4" 18 | }, 19 | "author": "carsonxu", 20 | "license": "ISC" 21 | } 22 | -------------------------------------------------------------------------------- /src/qcloud_sdk.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* CosCloud */ 4 | function CosCloud(opt) { 5 | this.appid = opt.appid; 6 | this.bucket = opt.bucket; 7 | this.region = opt.region; 8 | this.sign_url = opt.sign_url; 9 | this.progressInterval = opt.progressInterval || 1000; 10 | if (opt.getAppSign) { 11 | this.getAppSign = opt.getAppSign; 12 | } 13 | if (opt.getAppSignOnce) { 14 | this.getAppSignOnce = opt.getAppSignOnce; 15 | } 16 | } 17 | 18 | //512K 19 | var SLICE_SIZE_512K = 524288; 20 | //1M 21 | var SLICE_SIZE_1M = 1048576; 22 | //2M 23 | var SLICE_SIZE_2M = 2097152; 24 | //3M 25 | var SLICE_SIZE_3M = 3145728; 26 | //20M 大于20M的文件需要进行分片传输 27 | var MAX_UNSLICE_FILE_SIZE = 20971520; 28 | 29 | CosCloud.prototype.cosapi_cgi_url = "https://REGION.file.myqcloud.com/files/v2/"; 30 | CosCloud.prototype.sliceSize = 3 * 1024 * 1024; 31 | CosCloud.prototype.getExpired = function (second) { 32 | return parseInt(Date.now() / 1000) + (second || 60); 33 | }; 34 | 35 | 36 | CosCloud.prototype.set = function (opt) { 37 | 38 | if (opt) { 39 | this.appid = opt.appid; 40 | this.bucket = opt.bucket; 41 | this.region = opt.region; 42 | this.sign_url = opt.sign_url; 43 | if (opt.getAppSign) { 44 | this.getAppSign = opt.getAppSign; 45 | } 46 | if (opt.getAppSignOnce) { 47 | this.getAppSignOnce = opt.getAppSignOnce; 48 | } 49 | } 50 | }; 51 | 52 | CosCloud.prototype.getCgiUrl = function (destPath) { 53 | var region = this.region; 54 | var bucket = this.bucket; 55 | var url = this.cosapi_cgi_url; 56 | url = url.replace('REGION', region); 57 | 58 | return url + this.appid + '/' + bucket + '/' + destPath; 59 | 60 | }; 61 | 62 | CosCloud.prototype.updateFolder = function (success, error, bucketName, remotePath, bizAttribute) { 63 | remotePath = fixPath.call(this, remotePath, 'folder'); 64 | this.updateBase(success, error, bucketName, remotePath, bizAttribute); 65 | }; 66 | 67 | CosCloud.prototype.updateFile = function (success, error, bucketName, remotePath, bizAttribute) { 68 | remotePath = fixPath.call(this, remotePath); 69 | this.updateBase(success, error, bucketName, remotePath, bizAttribute); 70 | }; 71 | 72 | CosCloud.prototype.updateBase = function (success, error, bucketName, remotePath, bizAttribute, authority, customHeaders) { 73 | var that = this; 74 | that.getAppSignOnce(function (sign) { 75 | var url = that.getCgiUrl(remotePath); 76 | 77 | var data = { 78 | op: 'update' 79 | }; 80 | 81 | if (bizAttribute) { 82 | data.biz_attr = bizAttribute; 83 | } 84 | //authority 权限类型,可选参数,可选值为eInvalid,eWRPrivate,eWPrivateRPublic 85 | // 文件可以与bucket拥有不同的权限类型,已经设置过权限的文件如果想要撤销,直接赋值为eInvalid,则会采用bucket的权限 86 | if (authority) { 87 | data.authority = authority; 88 | } 89 | 90 | if (customHeaders) { 91 | customHeaders = JSON.stringify(customHeaders); 92 | data.customHeaders = customHeaders; 93 | } 94 | 95 | wx.request({ 96 | method: 'POST', 97 | url: url, 98 | header: {'Authorization': sign}, 99 | data: data, 100 | success: success, 101 | fail: error 102 | }); 103 | }); 104 | }; 105 | 106 | CosCloud.prototype.deleteFolder = function (success, error, bucketName, remotePath) { 107 | remotePath = fixPath.call(this, remotePath, 'folder'); 108 | this.deleteBase(success, error, bucketName, remotePath); 109 | }; 110 | 111 | CosCloud.prototype.deleteFile = function (success, error, bucketName, remotePath) { 112 | remotePath = fixPath.call(this, remotePath); 113 | this.deleteBase(success, error, bucketName, remotePath); 114 | }; 115 | 116 | CosCloud.prototype.deleteBase = function (success, error, bucketName, remotePath) { 117 | if (remotePath == "/") { 118 | error({"code": 10003, "message": "不能删除Bucket"}); 119 | return; 120 | } 121 | var that = this; 122 | this.getAppSignOnce(function (sign) { 123 | var url = that.getCgiUrl(remotePath); 124 | var data = { 125 | op: 'delete' 126 | }; 127 | wx.request({ 128 | method: 'POST', 129 | url: url, 130 | header: {'Authorization': sign}, 131 | data: data, 132 | success: success, 133 | fail: error 134 | }); 135 | }); 136 | }; 137 | 138 | CosCloud.prototype.getFolderStat = function (success, error, bucketName, remotePath) { 139 | remotePath = fixPath(remotePath, 'folder'); 140 | this.statBase(success, error, bucketName, remotePath); 141 | }; 142 | 143 | CosCloud.prototype.getFileStat = function (success, error, bucketName, remotePath) { 144 | remotePath = fixPath(remotePath); 145 | this.statBase(success, error, bucketName, remotePath); 146 | }; 147 | 148 | CosCloud.prototype.statBase = function (success, error, bucketName, remotePath) { 149 | var that = this; 150 | this.getAppSign.call(that, function (sign) { 151 | var url = that.getCgiUrl(remotePath); 152 | var data = { 153 | op: "stat" 154 | }; 155 | wx.request({ 156 | url: url, 157 | method: "GET", 158 | header: {'Authorization': sign}, 159 | data: data, 160 | success: success, 161 | fail: error 162 | }); 163 | }); 164 | 165 | }; 166 | 167 | CosCloud.prototype.createFolder = function (success, error, bucketName, remotePath, bizAttr) { 168 | var that = this; 169 | this.getAppSign(function (sign) { 170 | remotePath = fixPath(remotePath, 'folder'); 171 | var url = that.getCgiUrl(remotePath); 172 | var data = { 173 | op: 'create', 174 | biz_attr: bizAttr || '' 175 | }; 176 | wx.request({ 177 | method: 'POST', 178 | url: url, 179 | header: {'Authorization': sign}, 180 | data: data, 181 | success: success, 182 | fail: error 183 | }); 184 | }); 185 | }; 186 | 187 | CosCloud.prototype.copyFile = function (success, error, bucketName, remotePath, destPath, overWrite) { 188 | var that = this; 189 | this.getAppSign(function (sign) { 190 | remotePath = fixPath(remotePath); 191 | var url = that.getCgiUrl(remotePath); 192 | var data = { 193 | op: 'copy', 194 | dest_fileid: destPath, 195 | to_over_write: overWrite 196 | }; 197 | 198 | wx.request({ 199 | method: 'POST', 200 | url: url, 201 | header: {'Authorization': sign}, 202 | data: data, 203 | success: success, 204 | fail: error 205 | }); 206 | }); 207 | }; 208 | 209 | CosCloud.prototype.moveFile = function (success, error, bucketName, remotePath, destPath, overWrite) { 210 | var that = this; 211 | this.getAppSign(function (sign) { 212 | remotePath = fixPath(remotePath); 213 | var url = that.getCgiUrl(remotePath); 214 | var data = { 215 | op: 'move', 216 | dest_fileid: destPath, 217 | to_over_write: overWrite 218 | }; 219 | 220 | wx.request({ 221 | method: 'POST', 222 | url: url, 223 | header: {'Authorization': sign}, 224 | data: data, 225 | success: success, 226 | fail: error 227 | }); 228 | }); 229 | }; 230 | 231 | CosCloud.prototype.getFolderList = function (success, error, bucketName, remotePath, num, context, order, pattern, prefix) { 232 | var that = this; 233 | 234 | remotePath = fixPath(remotePath, 'folder'); 235 | 236 | that.listBase(success, error, bucketName, remotePath, num, context, order, pattern); 237 | }; 238 | 239 | CosCloud.prototype.listBase = function (success, error, bucketName, remotePath, num, context, order, pattern, prefix) { 240 | var that = this; 241 | that.getAppSign(function (sign) { 242 | var url = that.getCgiUrl(remotePath); 243 | 244 | num = num || 20; 245 | context = context || ''; 246 | order = order || 0; 247 | pattern = pattern || 'eListBoth'; 248 | 249 | var data = { 250 | op: "list", 251 | num: num, 252 | context: context, 253 | order: order, 254 | pattern: pattern 255 | }; 256 | wx.request({ 257 | url: url, 258 | method: "GET", 259 | header: {'Authorization': sign}, 260 | data: data, 261 | success: success, 262 | fail: error 263 | }); 264 | }); 265 | }; 266 | 267 | CosCloud.prototype.uploadFile = function (success, error, bucketName, remotePath, tempFilePath, insertOnly) { 268 | 269 | var options = {}; 270 | var bizAttr = {}; 271 | var onProgress; 272 | if (typeof success === 'object') { 273 | options = success; 274 | bizAttr = options.bizAttr; 275 | success = options.success; 276 | error = options.error; 277 | bucketName = options.bucket; 278 | remotePath = options.path; 279 | tempFilePath = options.filepath; 280 | insertOnly = options.insertOnly; 281 | if (options.onProgress && (typeof options.onProgress === 'function')) { 282 | onProgress = (function () { 283 | var time0 = Date.now(); 284 | var size0 = 0; 285 | var FinishSize = 0; 286 | var FileSize = 0; 287 | var progressTimer; 288 | var update = function () { 289 | progressTimer = 0; 290 | var time1 = Date.now(); 291 | var speed = parseInt((FinishSize - size0) / ((time1 - time0) / 1000) * 100) / 100 || 0; 292 | var percent = parseInt(FinishSize / FileSize * 100) / 100 || 0; 293 | time0 = time1; 294 | size0 = FinishSize; 295 | try { 296 | options.onProgress({ 297 | loaded: FinishSize, 298 | total: FileSize, 299 | speed: speed, 300 | percent: percent 301 | }); 302 | } catch (e) { 303 | } 304 | }; 305 | return function (info, immediately) { 306 | if (info) { 307 | FinishSize = info.totalBytesSent; 308 | FileSize = info.totalBytesExpectedToSend; 309 | } 310 | if (immediately) { 311 | if (progressTimer) { 312 | clearTimeout(progressTimer); 313 | update(); 314 | } 315 | } else { 316 | if (progressTimer) return; 317 | progressTimer = setTimeout(update, that.progressInterval || 1000); 318 | } 319 | }; 320 | })(); 321 | } 322 | } 323 | 324 | var that = this; 325 | remotePath = fixPath(remotePath); 326 | that.getAppSign(function (sign) { 327 | var url = that.getCgiUrl(remotePath); 328 | var data = { 329 | op: 'upload' 330 | }; 331 | if (insertOnly >= 0) {//insertOnly==0 表示允许覆盖文件 1表示不允许 其他值忽略 332 | data['insertOnly'] = insertOnly; 333 | } 334 | if (bizAttr) { 335 | data['biz_attr'] = bizAttr; 336 | } 337 | var uploadTask = wx.uploadFile({ 338 | url: url, 339 | filePath: tempFilePath, 340 | name: 'fileContent', 341 | header: {'Authorization': sign}, 342 | formData: data, 343 | success: function (result) { 344 | result.data = JSON.parse(result.data); 345 | onProgress(null, true); 346 | success.call(this, result); 347 | }, 348 | fail: error 349 | }); 350 | onProgress && uploadTask && uploadTask.onProgressUpdate && uploadTask.onProgressUpdate(onProgress); 351 | }); 352 | }; 353 | 354 | //处理路径 355 | function fixPath(path, type) { 356 | 357 | if (!path) { 358 | return ''; 359 | } 360 | var self = this; 361 | path = path.replace(/(^\/*)|(\/*$)/g, ''); 362 | if (type == 'folder') { 363 | path = encodeURIComponent(path + '/').replace(/%2F/g, '/'); 364 | } else { 365 | path = encodeURIComponent(path).replace(/%2F/g, '/'); 366 | } 367 | 368 | if (self) { 369 | self.path = '/' + self.appid + '/' + self.bucket + '/' + path; 370 | } 371 | 372 | return path; 373 | } 374 | 375 | module.exports = CosCloud; --------------------------------------------------------------------------------