├── demo-album
├── app.js
├── pages
│ ├── album
│ │ ├── album.json
│ │ ├── album.wxml
│ │ ├── album.wxss
│ │ └── album.js
│ ├── preview
│ │ ├── preview.json
│ │ ├── preview.wxml
│ │ ├── preview.wxss
│ │ └── preview.js
│ └── index
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.js
├── lib
│ ├── api.js
│ ├── request.js
│ ├── cos.js
│ └── util.js
├── images
│ ├── wave.png
│ └── camera.png
├── app.wxss
├── config.js
├── sitemap.json
├── .gitignore
├── app.json
└── project.config.json
├── demo
├── pages
│ └── index
│ │ ├── index.json
│ │ ├── index.wxss
│ │ ├── index.wxml
│ │ └── index.js
├── config.js
├── sitemap.json
├── app.wxss
├── app.json
├── demo-ci.js
├── app.js
├── project.config.json
├── ciDemo
│ ├── mediaProcess.js
│ ├── other.js
│ ├── audit.js
│ ├── asr.js
│ ├── docPreview.js
│ └── fileProcess.js
├── demo-post-policy.js
├── tools.js
├── lib
│ ├── cos-auth.js
│ └── beacon_mp.min.js
└── demo-sdk.js
├── .babelrc
├── index.js
├── .gitignore
├── .npmignore
├── .prettierrc
├── scripts
└── patch-check.js
├── patches
└── fast-xml-parser+4.5.0.patch
├── src
├── event.js
├── async.js
├── session.js
├── cos.js
├── task.js
└── tracker.js
├── LICENSE
├── package.json
├── .github
└── workflows
│ └── auto-changelog.yml
├── README.md
├── lib
├── request.js
├── base64.js
└── crypto.js
└── server
└── sts.js
/demo-album/app.js:
--------------------------------------------------------------------------------
1 | App({});
--------------------------------------------------------------------------------
/demo/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/demo-album/pages/album/album.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/demo-album/lib/api.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | };
--------------------------------------------------------------------------------
/demo-album/pages/preview/preview.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var COS = require('./src/cos');
2 | module.exports = COS;
--------------------------------------------------------------------------------
/demo-album/images/wave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tencentyun/cos-wx-sdk-v5/HEAD/demo-album/images/wave.png
--------------------------------------------------------------------------------
/demo-album/images/camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tencentyun/cos-wx-sdk-v5/HEAD/demo-album/images/camera.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | .idea
3 | node_modules
4 | package-lock.json
5 | .DS_Store
6 | */.wechatide
7 | project.private.config.json
8 |
--------------------------------------------------------------------------------
/demo-album/app.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | background-color: #fff;
3 | }
4 | .main {
5 | position: relative;
6 | z-index: 2;
7 | margin: 40rpx 80rpx;
8 | }
--------------------------------------------------------------------------------
/demo/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stsUrl: 'https://example.com/sts.php',
3 | Bucket: 'test-1250000000',
4 | Region: 'ap-guangzhou',
5 | };
6 |
--------------------------------------------------------------------------------
/demo-album/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarBackgroundColor": "#2277da",
3 | "navigationBarTextStyle": "white",
4 | "backgroundColor": "white"
5 | }
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | .github/
4 | coverage/
5 | demo/
6 | demo-album/
7 | server/
8 | patches/
9 | .babelrc
10 | .prettierrc
11 | build.js
12 | CHANGELOG.md
--------------------------------------------------------------------------------
/demo-album/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stsUrl: 'https://example.com/sts.php',
3 | Bucket: 'test-1250000000',
4 | Region: 'ap-guangzhou',
5 | albumDir: 'album/',
6 | };
--------------------------------------------------------------------------------
/demo/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/demo-album/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/demo-album/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows
2 | [Dd]esktop.ini
3 | Thumbs.db
4 | $RECYCLE.BIN/
5 |
6 | # macOS
7 | .DS_Store
8 | .fseventsd
9 | .Spotlight-V100
10 | .TemporaryItems
11 | .Trashes
12 |
13 | # Node.js
14 | node_modules/
15 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": true,
7 | "jsxSingleQuote": true,
8 | "jsxBracketSameLine": true,
9 | "trailingComma": "es5"
10 | }
11 |
--------------------------------------------------------------------------------
/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/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 | "sitemapLocation": "sitemap.json"
12 | }
--------------------------------------------------------------------------------
/demo-album/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index",
4 | "pages/preview/preview",
5 | "pages/album/album"
6 | ],
7 | "window": {
8 | "navigationBarTitleText": "COS 上传示例",
9 | "windowBackground": "white",
10 | "navigationBarTextStyle": "white",
11 | "navigationBarBackgroundColor": "#373b3e"
12 | },
13 | "sitemapLocation": "sitemap.json"
14 | }
15 |
--------------------------------------------------------------------------------
/scripts/patch-check.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const exec = require('child_process').execSync;
4 |
5 | const patchesDir = path.join(__dirname, '../patches');
6 | const hasPatches = fs.existsSync(patchesDir);
7 |
8 | if (hasPatches) {
9 | // 执行补丁
10 | console.log('npx patch-package');
11 | exec('npx patch-package', { stdio: 'inherit' });
12 | } else {
13 | console.log('无补丁应用');
14 | }
--------------------------------------------------------------------------------
/demo-album/lib/request.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | module.exports = (options) => {
4 | return new Promise((resolve, reject) => {
5 | options = Object.assign(options, {
6 | success(result) {
7 | if (result.statusCode === 200) {
8 | resolve(result.data);
9 | } else {
10 | reject(result);
11 | }
12 | },
13 | fail: reject,
14 | });
15 | wx.request(options);
16 | });
17 | };
--------------------------------------------------------------------------------
/demo-album/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 简单上传
4 | 文件 3 天后删除
5 |
6 |
7 |
8 |
9 | 共享相册
10 |
11 |
12 |
13 | ● 上传对象到 COS 并获取下载地址
14 |
--------------------------------------------------------------------------------
/demo/demo-ci.js:
--------------------------------------------------------------------------------
1 | const asrDao = require('./ciDemo/asr');
2 | const auditDao = require('./ciDemo/audit');
3 | const docPreviewDao = require('./ciDemo/docPreview');
4 | const picProcessDao = require('./ciDemo/picProcess');
5 | const mediaProcessDao = require('./ciDemo/mediaProcess');
6 | const fileProcessDao = require('./ciDemo/fileProcess');
7 | const metaDao =require('./ciDemo/meta');
8 | const otherDao = require('./ciDemo/other');
9 |
10 | module.exports = {
11 | asrDao,
12 | auditDao,
13 | docPreviewDao,
14 | picProcessDao,
15 | mediaProcessDao,
16 | fileProcessDao,
17 | metaDao,
18 | otherDao
19 | };
--------------------------------------------------------------------------------
/patches/fast-xml-parser+4.5.0.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js b/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
2 | index 70db055..17536b7 100644
3 | --- a/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
4 | +++ b/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
5 | @@ -184,7 +184,7 @@ function buildAttributesMap(attrStr, jPath, tagName) {
6 | }
7 |
8 | const parseXml = function(xmlData) {
9 | - xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line
10 | + // xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line
11 | const xmlObj = new xmlNode('!xml');
12 | let currentNode = xmlObj;
13 | let textData = "";
14 |
--------------------------------------------------------------------------------
/demo-album/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "",
3 | "setting": {
4 | "urlCheck": true,
5 | "es6": true,
6 | "postcss": true,
7 | "minified": true,
8 | "newFeature": true,
9 | "babelSetting": {
10 | "ignore": [],
11 | "disablePlugins": [],
12 | "outputPath": ""
13 | },
14 | "coverView": false,
15 | "enhance": false,
16 | "showShadowRootInWxmlPanel": false,
17 | "packNpmRelationList": [],
18 | "ignoreUploadUnusedFiles": true
19 | },
20 | "compileType": "miniprogram",
21 | "condition": {},
22 | "editorSetting": {
23 | "tabIndent": "insertSpaces",
24 | "tabSize": 2
25 | },
26 | "libVersion": "2.28.0",
27 | "packOptions": {
28 | "ignore": [],
29 | "include": []
30 | },
31 | "appid": "wx0000000000000000"
32 | }
33 |
--------------------------------------------------------------------------------
/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-album/lib/cos.js:
--------------------------------------------------------------------------------
1 | var COS = require('./cos-wx-sdk-v5');
2 | var config = require('../config');
3 | var cos = new COS({
4 | getAuthorization: function (options, callback) {
5 | wx.request({
6 | method: 'GET',
7 | url: config.stsUrl, // 服务端签名,参考 server 目录下的两个签名例子
8 | dataType: 'json',
9 | success: function (result) {
10 | var data = result.data;
11 | callback({
12 | TmpSecretId: data.credentials && data.credentials.tmpSecretId,
13 | TmpSecretKey: data.credentials && data.credentials.tmpSecretKey,
14 | XCosSecurityToken: data.credentials && data.credentials.sessionToken,
15 | ExpiredTime: data.expiredTime,
16 | });
17 | }
18 | });
19 | },
20 | });
21 |
22 | module.exports = cos;
--------------------------------------------------------------------------------
/src/event.js:
--------------------------------------------------------------------------------
1 | var initEvent = function (cos) {
2 | var listeners = {};
3 | var getList = function (action) {
4 | !listeners[action] && (listeners[action] = []);
5 | return listeners[action];
6 | };
7 | cos.on = function (action, callback) {
8 | getList(action).push(callback);
9 | };
10 | cos.off = function (action, callback) {
11 | var list = getList(action);
12 | for (var i = list.length - 1; i >= 0; i--) {
13 | callback === list[i] && list.splice(i, 1);
14 | }
15 | };
16 | cos.emit = function (action, data) {
17 | var list = getList(action).map(function (cb) {
18 | return cb;
19 | });
20 | for (var i = 0; i < list.length; i++) {
21 | list[i](data);
22 | }
23 | };
24 | };
25 |
26 | var EventProxy = function () {
27 | initEvent(this);
28 | };
29 |
30 | module.exports.init = initEvent;
31 | module.exports.EventProxy = EventProxy;
32 |
--------------------------------------------------------------------------------
/demo-album/pages/preview/preview.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 上传成功
4 | {{url}}
5 |
6 | 复制 URL,可在浏览器中下载您上传的对象
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | .btn-content button {
3 | margin: 0 0 10px 0;
4 | border-radius: 0;
5 | }
6 | .title {
7 | display:block;
8 | box-sizing: border-box;
9 | padding: 0 5px;
10 | width: 100%;
11 | height: 30px;
12 | line-height: 30px;
13 | border-top: 1px solid #ccc;
14 | margin:auto;
15 | font-size:14px;
16 | color:#333;
17 | text-align: left;
18 | font-weight: bold;
19 | }
20 |
21 | .list-panel{
22 | width: 100%;
23 | }
24 |
25 | .sub-title{
26 | display:block;
27 | box-sizing: border-box;
28 | padding: 0 5px;
29 | width: 100%;
30 | height: 30px;
31 | line-height: 30px;
32 | font-size:12px;
33 | color:#333;
34 | text-align: left;
35 | font-weight: bold;
36 | }
37 |
38 | .list {
39 | margin-top: 10px;
40 | padding-bottom: 10px;
41 | width: 100%;
42 | }
43 |
44 | .button {
45 | float: left;
46 | margin: 0 3px 3px 0;
47 | text-align: left;
48 | font-size: 14px;
49 | height: 28px;
50 | line-height:28px;
51 | padding:0 10px;
52 | }
--------------------------------------------------------------------------------
/demo-album/lib/util.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // 一维数组转二维数组
3 | listToMatrix(list, elementsPerSubArray) {
4 | let matrix = [], i, col, row;
5 | for (i = 0, row = -1; i < list.length; i += 1) {
6 | col = i % elementsPerSubArray;
7 | row = Math.floor(i / elementsPerSubArray);
8 | if (!matrix[row]) matrix[row] = [0, 0, 0];
9 | matrix[row][col] = list[i];
10 | }
11 | return matrix;
12 | },
13 | // 选中文件之后,计算一个随机的短文件名
14 | getRandFileName: function (filePath) {
15 | var extIndex = filePath.lastIndexOf('.');
16 | var extName = extIndex === -1 ? '' : filePath.substr(extIndex);
17 | return parseInt('' + Date.now() + Math.floor(Math.random() * 900 + 100), 10).toString(36) + extName;
18 | },
19 | // 对更多字符编码的 url encode 格式
20 | camSafeUrlEncode: function (str) {
21 | return encodeURIComponent(str)
22 | .replace(/!/g, '%21')
23 | .replace(/'/g, '%27')
24 | .replace(/\(/g, '%28')
25 | .replace(/\)/g, '%29')
26 | .replace(/\*/g, '%2A');
27 | },
28 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present 腾讯云
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cos-wx-sdk-v5",
3 | "version": "1.8.0",
4 | "description": "小程序 SDK for [腾讯云对象存储服务](https://cloud.tencent.com/product/cos)",
5 | "main": "dist/cos-wx-sdk-v5.min.js",
6 | "scripts": {
7 | "prettier": "prettier --write src demo/demo-sdk.js demo/test.js demo/ciDemo",
8 | "dev": "cross-env NODE_ENV=development node build.js --mode=development",
9 | "build": "cross-env NODE_ENV=production node build.js --mode=production",
10 | "sts.js": "node server/sts.js",
11 | "postinstall": "node scripts/patch-check.js"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "http://github.com/tencentyun/cos-wx-sdk-v5.git"
16 | },
17 | "author": "carsonxu",
18 | "license": "ISC",
19 | "dependencies": {
20 | "fast-xml-parser": "4.5.0",
21 | "mime": "^2.4.6"
22 | },
23 | "devDependencies": {
24 | "@babel/core": "7.17.9",
25 | "@babel/preset-env": "7.16.11",
26 | "babel-loader": "8.2.5",
27 | "body-parser": "^1.18.3",
28 | "cross-env": "^7.0.3",
29 | "express": "^4.17.1",
30 | "patch-package": "^8.0.0",
31 | "prettier": "^3.0.1",
32 | "qcloud-cos-sts": "^3.0.2",
33 | "terser-webpack-plugin": "4.2.3",
34 | "webpack": "4.46.0",
35 | "webpack-cli": "4.10.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/async.js:
--------------------------------------------------------------------------------
1 | var eachLimit = function (arr, limit, iterator, callback) {
2 | callback = callback || function () {};
3 | if (!arr.length || limit <= 0) {
4 | return callback();
5 | }
6 |
7 | var completed = 0;
8 | var started = 0;
9 | var running = 0;
10 |
11 | (function replenish() {
12 | if (completed >= arr.length) {
13 | return callback();
14 | }
15 |
16 | while (running < limit && started < arr.length) {
17 | started += 1;
18 | running += 1;
19 | iterator(arr[started - 1], function (err) {
20 | if (err) {
21 | callback(err);
22 | callback = function () {};
23 | } else {
24 | completed += 1;
25 | running -= 1;
26 | if (completed >= arr.length) {
27 | callback();
28 | } else {
29 | replenish();
30 | }
31 | }
32 | });
33 | }
34 | })();
35 | };
36 |
37 | var retry = function (times, iterator, callback) {
38 | var next = function (index) {
39 | iterator(function (err, data) {
40 | if (err && index < times) {
41 | next(index + 1);
42 | } else {
43 | callback(err, data);
44 | }
45 | });
46 | };
47 | if (times < 1) {
48 | callback();
49 | } else {
50 | next(1);
51 | }
52 | };
53 |
54 | var async = {
55 | eachLimit: eachLimit,
56 | retry: retry,
57 | };
58 |
59 | module.exports = async;
60 |
--------------------------------------------------------------------------------
/demo/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 简单上传例子(推荐)
9 |
10 |
11 |
12 | 小程序完整 SDK 例子(功能齐全,文件较大)
13 |
14 | {{title[index]}} {{key}}
15 |
16 |
17 |
18 |
19 |
20 |
21 | 数据万象示例
22 |
23 | {{ciTitle[index]}} {{key}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/.github/workflows/auto-changelog.yml:
--------------------------------------------------------------------------------
1 | name: ChangeLog
2 |
3 | on:
4 | workflow_dispatch:
5 | release:
6 | types: [published]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/setup-node@v2-beta
15 | with:
16 | node-version: '12'
17 | - uses: actions/checkout@v2
18 | with:
19 | fetch-depth: 0
20 |
21 | - name: Checkout Tool
22 | uses: actions/checkout@v2
23 | with:
24 | repository: konakonall/auto-changelog
25 | path: 'auto-changelog'
26 | - name: Build Tool
27 | run: |
28 | cd auto-changelog
29 | npm install
30 | npm link
31 |
32 | - name: Generate ChangeLog
33 | env: # Or as an environment variable
34 | TOKEN: ${{ secrets.GITHUB_TOKEN }}
35 | run: |
36 | auto-changelog --token $TOKEN
37 | - name: Cat ChangeLog
38 | run: cat CHANGELOG.md
39 |
40 | - name: Commit files
41 | env:
42 | CI_USER: "gouki0123"
43 | CI_EMAIL: "gouki0123@gmail.com"
44 | run: |
45 | git config --local user.email "$CI_EMAIL"
46 | git config --local user.name "$CI_USER"
47 | git add CHANGELOG.md && git commit -m 'Updated CHANGELOG.md' && echo "push=1" >> $GITHUB_ENV || echo "No changes to CHANGELOG.md"
48 |
49 | - name: Push changes
50 | if: env.push == 1
51 | env:
52 | CI_USER: "gouki0123"
53 | CI_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54 | run: |
55 | git push "https://$CI_USER:$CI_TOKEN@github.com/$GITHUB_REPOSITORY.git" HEAD:master
56 |
--------------------------------------------------------------------------------
/demo/pages/index/index.js:
--------------------------------------------------------------------------------
1 | //index.js
2 | var cosDemoSdk = require('../../demo-sdk');
3 | var ciDemoSdk = require('../../demo-ci');
4 | var postUpload = require('../../demo-post-policy');
5 |
6 | var option = {
7 | data: {
8 | demoType: 'cos',
9 | listMap: {},
10 | title: {
11 | toolsDao: '工具函数',
12 | bucketDao: '存储桶操作',
13 | objectDao: '对象操作',
14 | advanceObjectDao: '高级操作',
15 | ciObjectDao: '数据万象示例',
16 | },
17 | ciListMap: {},
18 | ciTitle: {
19 | asrDao: '智能语音',
20 | auditDao: '内容审核',
21 | docPreviewDao: '文档预览',
22 | picProcessDao: '图片处理',
23 | mediaProcessDao: '媒体处理',
24 | fileProcessDao: '文件处理',
25 | metaDao: '智能检索',
26 | otherDao: '其他',
27 | },
28 | },
29 | switchCosDemo() {
30 | this.setData({ demoType: 'cos' });
31 | },
32 | switchCiDemo() {
33 | this.setData({ demoType: 'ci' });
34 | },
35 | };
36 |
37 | for (var key in cosDemoSdk) {
38 | if (cosDemoSdk.hasOwnProperty(key)) {
39 | var sublist = [];
40 | var subDemoSdk = cosDemoSdk[key];
41 | for (var subkey in subDemoSdk) {
42 | sublist.push(subkey);
43 | option[subkey] = subDemoSdk[subkey];
44 | }
45 | option.data.listMap[key] = sublist;
46 | }
47 | }
48 |
49 | for (var key in ciDemoSdk) {
50 | if (ciDemoSdk.hasOwnProperty(key)) {
51 | var sublist = [];
52 | var subDemoSdk = ciDemoSdk[key];
53 | for (var subkey in subDemoSdk) {
54 | sublist.push(subkey);
55 | option[subkey] = subDemoSdk[subkey];
56 | }
57 | option.data.ciListMap[key] = sublist;
58 | }
59 | }
60 |
61 | option.postUpload = postUpload;
62 |
63 | //获取应用实例
64 | Page(option);
65 |
--------------------------------------------------------------------------------
/demo-album/pages/preview/preview.wxss:
--------------------------------------------------------------------------------
1 | .preview {
2 | width: 100%;
3 | height: 100%;
4 | background: #fff;
5 | }
6 |
7 | .preview-success {
8 | display: inline-block;
9 | font-size: 40rpx;
10 | }
11 |
12 | .preview-url {
13 | border: 1px solid #ddd;
14 | padding: 16rpx;
15 | background: #f7f7f7;
16 | word-break:break-all;
17 | font-size: 32rpx;
18 | border-radius: 5rpx;
19 | margin-top: 40rpx;
20 | }
21 |
22 | .preview-tips {
23 | margin-top: 20rpx;
24 | font-size: 30rpx;
25 | color: #888;
26 | }
27 |
28 | .preview-button-wrap {
29 | margin-top: 30rpx;
30 | text-align: left;
31 | }
32 |
33 | .preview-button {
34 | display: inline-block;
35 | position:relative;
36 | text-align: center;
37 | box-sizing:border-box;
38 | font-size:32rpx;
39 | text-decoration:none;
40 | -webkit-tap-highlight-color:transparent;
41 | overflow:hidden;
42 | width:280rpx;
43 | height:85rpx;
44 | background-color:#fff;
45 | color:#2277da;
46 | line-height:85rpx;
47 | border-radius: 5rpx;
48 | }
49 |
50 | .preview-button:first-child {
51 | margin-right: 20rpx;
52 | }
53 |
54 | .preview-outer {
55 | margin-top: 50rpx;
56 | position: relative;
57 | text-align: center;
58 | width: 590rpx;
59 | }
60 |
61 | .preview-inner {
62 | padding-top: 50rpx;
63 | position: relative;
64 | text-align: center;
65 | width: 590rpx;
66 | }
67 |
68 | .preview-image {
69 | display:block;
70 | margin: 0 auto;
71 | width: 590rpx;
72 | height: 590rpx;
73 | }
74 |
75 | .preview-video {
76 | margin-top: 30rpx;
77 | display:block;
78 | margin: 0 auto;
79 | width: 590rpx;
80 | height: 415rpx;
81 | }
--------------------------------------------------------------------------------
/demo/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "setting": {
4 | "urlCheck": false,
5 | "es6": false,
6 | "enhance": false,
7 | "postcss": false,
8 | "preloadBackgroundData": false,
9 | "minified": false,
10 | "newFeature": true,
11 | "coverView": true,
12 | "nodeModules": false,
13 | "autoAudits": false,
14 | "showShadowRootInWxmlPanel": true,
15 | "scopeDataCheck": false,
16 | "uglifyFileName": false,
17 | "checkInvalidKey": true,
18 | "checkSiteMap": true,
19 | "uploadWithSourceMap": true,
20 | "compileHotReLoad": false,
21 | "useMultiFrameRuntime": true,
22 | "useApiHook": true,
23 | "useApiHostProcess": true,
24 | "babelSetting": {
25 | "ignore": [],
26 | "disablePlugins": [],
27 | "outputPath": ""
28 | },
29 | "enableEngineNative": false,
30 | "useIsolateContext": true,
31 | "useCompilerModule": true,
32 | "userConfirmedUseCompilerModuleSwitch": false,
33 | "userConfirmedBundleSwitch": false,
34 | "packNpmManually": false,
35 | "packNpmRelationList": [],
36 | "minifyWXSS": true,
37 | "disableUseStrict": false,
38 | "showES6CompileOption": false,
39 | "useCompilerPlugins": false,
40 | "ignoreUploadUnusedFiles": false,
41 | "useStaticServer": true,
42 | "condition": false
43 | },
44 | "compileType": "miniprogram",
45 | "libVersion": "2.24.0",
46 | "appid": "wx0000000000000000",
47 | "projectname": "demo",
48 | "simulatorType": "wechat",
49 | "simulatorPluginLibVersion": {},
50 | "condition": {},
51 | "packOptions": {
52 | "ignore": [],
53 | "include": []
54 | },
55 | "editorSetting": {
56 | "tabIndent": "insertSpaces",
57 | "tabSize": 2
58 | }
59 | }
--------------------------------------------------------------------------------
/demo-album/pages/preview/preview.js:
--------------------------------------------------------------------------------
1 | Page({
2 | data: {
3 | type: 'image',
4 | url: '',
5 | showPreview: false,
6 | },
7 | onShareAppMessage: function (res) {
8 | var typeMap = {
9 | image: '图片',
10 | video: '视频',
11 | };
12 | var data = {
13 | title: 'COS 上传示例 - 预览' + (typeMap[this.data.type] || '文件'),
14 | path: this.route + '?type=' + this.data.type + '&url=' + encodeURIComponent(this.data.url),
15 | };
16 | if (this.data.type === 'image') {
17 | data.imageUrl = this.data.url;
18 | }
19 | return data;
20 | },
21 | onShow() {
22 | this.setData({showPreview: false});
23 | this.setData({
24 | type: this.options.type || 'image',
25 | url: decodeURIComponent(this.options.url) || '',
26 | });
27 | },
28 | showPreviewBox() {
29 | this.setData({showPreview: true});
30 | },
31 | copyLink() {
32 | wx.setClipboardData({
33 | data: this.data.url || '',
34 | success: function () {
35 | wx.showToast({title: '复制成功', icon: 'success', duration: 2000});
36 | },
37 | fail: function () {
38 | wx.showToast({title: '复制失败', icon: 'error', duration: 2000});
39 | },
40 | });
41 | },
42 | saveImage() {
43 | wx.downloadFile({
44 | url: this.data.url,
45 | success: function(res) {
46 | // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
47 | if (res.statusCode === 200) {
48 | wx.saveImageToPhotosAlbum({
49 | filePath: res.tempFilePath,
50 | });
51 | }
52 | }
53 | });
54 | },
55 | });
--------------------------------------------------------------------------------
/demo-album/pages/album/album.wxml:
--------------------------------------------------------------------------------
1 |
2 | 上传图片到 COS 共享给他人查看,长按图片可删除
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 上传图片
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 保存到本地
35 | 删除图片
36 | 取消
37 |
38 |
39 | {{loadingMessage}}
40 | {{toastMessage}}
--------------------------------------------------------------------------------
/demo/ciDemo/mediaProcess.js:
--------------------------------------------------------------------------------
1 | const COS = require('../lib/cos-wx-sdk-v5');
2 | var wxfs = wx.getFileSystemManager();
3 | const config = require('../config');
4 | const { cos, requestCallback } = require('../tools');
5 |
6 | const mediaProcessDao = {
7 | 'describeMediaBuckets 查询已经开通数据万象功能的存储桶': describeMediaBuckets,
8 | 'getMediaInfo 获取媒体文件信息': getMediaInfo,
9 | 'getSnapshot 获取媒体文件某个时间的截图': getSnapshot,
10 | };
11 |
12 | function describeMediaBuckets() {
13 | var host = 'ci.' + config.Region + '.myqcloud.com';
14 | var url = 'https://' + host + '/mediabucket';
15 | cos.request(
16 | {
17 | Bucket: config.Bucket,
18 | Region: config.Region,
19 | Method: 'GET',
20 | Key: 'mediabucket' /** 固定值,必须 */,
21 | Url: url,
22 | Query: {
23 | pageNumber: '1' /** 第几页,非必须 */,
24 | pageSize: '10' /** 每页个数,非必须 */,
25 | // regions: 'ap-chengdu', /** 地域信息,例如'ap-beijing',支持多个值用逗号分隔如'ap-shanghai,ap-beijing',非必须 */
26 | // bucketNames: 'test-1250000000', /** 存储桶名称,精确搜索,例如'test-1250000000',支持多个值用逗号分隔如'test1-1250000000,test2-1250000000',非必须 */
27 | // bucketName: 'test', /** 存储桶名称前缀,前缀搜索,例如'test',支持多个值用逗号分隔如'test1,test2',非必须 */
28 | },
29 | },
30 | function (err, data) {
31 | console.log(err || data);
32 | }
33 | );
34 | }
35 |
36 | function getMediaInfo() {
37 | cos.request(
38 | {
39 | Bucket: config.Bucket,
40 | Region: config.Region,
41 | Method: 'GET',
42 | Key: 'test.mp4',
43 | Query: {
44 | 'ci-process': 'videoinfo' /** 固定值,必须 */,
45 | },
46 | },
47 | function (err, data) {
48 | console.log(err || data);
49 | }
50 | );
51 | }
52 |
53 | function getSnapshot() {
54 | cos.request(
55 | {
56 | Bucket: config.Bucket,
57 | Region: config.Region,
58 | Method: 'GET',
59 | Key: 'test.mp4',
60 | Query: {
61 | 'ci-process': 'snapshot' /** 固定值,必须 */,
62 | time: 1 /** 截图的时间点,单位为秒,必须 */,
63 | // width: 0, /** 截图的宽,非必须 */
64 | // height: 0, /** 截图的高,非必须 */
65 | // format: 'jpg', /** 截图的格式,支持 jpg 和 png,默认 jpg,非必须 */
66 | // rotate: 'auto', /** 图片旋转方式,默认为'auto',非必须 */
67 | // mode: 'exactframe', /** 截帧方式,默认为'exactframe',非必须 */
68 | },
69 | RawBody: true,
70 | DataType: 'arraybuffer',
71 | },
72 | function (err, data) {
73 | if (err) {
74 | console.log(err);
75 | } else {
76 | const imgBase64 = wx.arrayBufferToBase64(data.Body);
77 | console.log(imgBase64);
78 | }
79 | }
80 | );
81 | }
82 |
83 | module.exports = mediaProcessDao;
84 |
--------------------------------------------------------------------------------
/demo-album/pages/album/album.wxss:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 100%;
3 | height: 100%;
4 | min-height: 242rpx;
5 | }
6 |
7 | .album-container {
8 | margin: 3rpx;
9 | min-height: 242rpx;
10 | marring-top: 83rpx;
11 | }
12 |
13 | .item-group {
14 | display: flex;
15 | }
16 |
17 | .album-item {
18 | flex: 1;
19 | text-align: center;
20 | margin: 3rpx;
21 | width: 242rpx;
22 | height: 242rpx;
23 | line-height: 242rpx;
24 | }
25 |
26 | .album-item.empty {
27 | background: transparent;
28 | }
29 |
30 | .upload-tips {
31 | color: #888;
32 | display: block;
33 | font-size: 30rpx;
34 | height: 80rpx;
35 | line-height: 80rpx;
36 | margin: 0 20rpx;
37 | }
38 | .upload-wrap {
39 | color: #ccc;
40 | background-color: #fff;
41 | border: 1px solid #888;
42 | position: absolute;
43 | left: 6rpx;
44 | top: 86rpx;
45 | width: 240rpx;
46 | height: 239rpx;
47 | text-align: center;
48 | line-height: 240rpx;
49 | overflow: hidden;
50 | }
51 | .upload-add-outer {
52 | display: inline-block;
53 | flex: 1;
54 | text-align: center;
55 | margin: 3rpx;
56 | width: 242rpx;
57 | height: 242rpx;
58 | line-height: 242rpx;
59 | }
60 | .upload-add {
61 | display: block;
62 | position: relative;
63 | text-align: center;
64 | margin: 3rpx;
65 | width: 242rpx;
66 | height: 240rpx;
67 | border: 1rpx solid #ccc;
68 | line-height: 240rpx;
69 | color: #ccc;
70 | overflow: hidden;
71 | box-sizing:border-box;
72 | }
73 |
74 | .upload-add image {
75 | position: absolute;
76 | left: 0;
77 | width: 240rpx;
78 | height: 2.6rem;
79 | top: 1.2rem;
80 | }
81 |
82 | .upload-add text {
83 | position: absolute;
84 | width: 240rpx;
85 | height: 2rem;
86 | left: 0;
87 | top: 1.6rem;
88 | color: #888;
89 | }
90 |
91 | .upload-image {
92 | color: #ccc;
93 | background-color: #fff;
94 | border: 1px solid #888;
95 | position: absolute;
96 | left: 6rpx;
97 | top: 86rpx;
98 | width: 240rpx;
99 | height: 239rpx;
100 | text-align: center;
101 | line-height: 240rpx;
102 | overflow: hidden;
103 | }
104 |
105 | .upload-image image {
106 | position: absolute;
107 | left: 0;
108 | width: 242rpx;
109 | height: 2.6rem;
110 | top: 1.2rem;
111 | }
112 |
113 | .upload-image text {
114 | position: absolute;
115 | width: 242rpx;
116 | height: 2rem;
117 | left: 0;
118 | top: 1.6rem;
119 | color: #888;
120 | }
121 |
122 | .swiper-container {
123 | position: fixed;
124 | left: 0;
125 | top: 0;
126 | width: 100%;
127 | height: 100%;
128 | background: #000;
129 | }
130 |
131 | .swiper-container image {
132 | width: 100%;
133 | height: 100%;
134 | }
135 |
136 | action-sheet-item.warn {
137 | color: #e64340;
138 | }
--------------------------------------------------------------------------------
/demo-album/pages/index/index.js:
--------------------------------------------------------------------------------
1 | var util = require('../../lib/util');
2 | var config = require('../../config');
3 | var cos = require('../../lib/cos');
4 |
5 | Page({
6 | onLoad: function () {
7 | },
8 | onShareAppMessage: function (res) {
9 | return {
10 | title: 'COS 上传示例',
11 | path: this.route,
12 | }
13 | },
14 | // 前往相册页
15 | uploadImage() {
16 | wx.chooseImage({
17 | count: 1,
18 | camera: 'back',
19 | sizeType: ['compressed'],
20 | sourceType: ['album', 'camera'],
21 | success: function (res) {
22 | var filePath = res.tempFilePaths[0];
23 | if (filePath) {
24 | var Key = util.getRandFileName(filePath);
25 | wx.showLoading({title: '正在上传...'});
26 | cos.postObject({
27 | Bucket: config.Bucket,
28 | Region: config.Region,
29 | Key: Key,
30 | FilePath: filePath,
31 | }, function (err, data) {
32 | wx.hideLoading();
33 | if (data && data.Location) {
34 | wx.navigateTo({url: '../preview/preview?type=image&url=' + encodeURIComponent('https://' + data.Location)});
35 | } else {
36 | wx.showToast({title: '上传失败', icon: 'error', duration: 2000});
37 | }
38 | });
39 | }
40 | }
41 | })
42 | },
43 | // 前往相册页
44 | uploadVideo() {
45 | wx.chooseVideo({
46 | count: 1,
47 | sizeType: ['compressed'],
48 | sourceType: ['album', 'camera'],
49 | maxDuration: 60,
50 | camera: 'back',
51 | success: function (res) {
52 | var filePath = res.tempFilePath;
53 | if (filePath) {
54 | var Key = util.getRandFileName(filePath);
55 | wx.showLoading({title: '正在上传...'});
56 | cos.postObject({
57 | Bucket: config.Bucket,
58 | Region: config.Region,
59 | Key: Key,
60 | FilePath: filePath,
61 | }, function (err, data) {
62 | wx.hideLoading();
63 | if (data && data.Location) {
64 | wx.navigateTo({url: '../preview/preview?type=video&url=' + encodeURIComponent('https://' + data.Location)});
65 | } else {
66 | wx.showToast({title: '上传失败', icon: 'error', duration: 2000});
67 | }
68 | });
69 | }
70 | }
71 | });
72 | },
73 | // 前往相册页
74 | gotoAlbum() {
75 | wx.navigateTo({url: '../album/album'});
76 | },
77 | });
78 |
--------------------------------------------------------------------------------
/demo/ciDemo/other.js:
--------------------------------------------------------------------------------
1 | const COS = require('../lib/cos-wx-sdk-v5');
2 | var wxfs = wx.getFileSystemManager();
3 | const config = require('../config');
4 | const { cos, requestCallback } = require('../tools');
5 |
6 | const otherDao = {
7 | '提交病毒检测任务 postVirusDetect': postVirusDetect,
8 | '查询病毒检测任务结果 getVirusDetectResult': getVirusDetectResult,
9 | '查询防盗链 describeRefer': describeRefer,
10 | '设置防盗链 setRefer': setRefer,
11 | };
12 |
13 | function postVirusDetect() {
14 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/virus/detect';
15 | var url = 'https://' + host;
16 | var body = COS.util.json2xml({
17 | Request: {
18 | Input: {
19 | Object: 'test/1.png', // 文件名,取值为文件在当前存储桶中的完整名称,与Url参数二选一
20 | // Url: 'http://examplebucket-1250000000.cos.ap-shanghai.myqcloud.com/virus.doc', // 病毒文件的链接地址,与Object参数二选一
21 | },
22 | Conf: {
23 | DetectType: 'Virus', // 检测的病毒类型,当前固定为:Virus
24 | // CallBack: 'http://callback.demo.com', // 任务回调的地址
25 | },
26 | },
27 | });
28 | cos.request(
29 | {
30 | Method: 'POST',
31 | Key: 'virus/detect',
32 | Url: url,
33 | Body: body,
34 | ContentType: 'application/xml',
35 | },
36 | function (err, data) {
37 | console.log(err || data);
38 | }
39 | );
40 | }
41 |
42 | function getVirusDetectResult() {
43 | var jobId = 'ss5a8d3065bd9011eda1445254009dadxx'; // 提交病毒检测任务后会返回当前任务的jobId
44 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/virus/detect/' + jobId;
45 | var url = 'https://' + host;
46 | cos.request(
47 | {
48 | Method: 'GET',
49 | Key: 'virus/detect/' + jobId,
50 | Url: url,
51 | },
52 | function (err, data) {
53 | console.log(err || data);
54 | }
55 | );
56 | }
57 |
58 | function describeRefer() {
59 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
60 | const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?hotlink';
61 | const url = 'https://' + host;
62 | cos.request(
63 | {
64 | Method: 'GET', // 固定值,必须
65 | Url: url, // 请求的url,必须
66 | },
67 | function (err, data) {
68 | if (err) {
69 | // 处理请求失败
70 | console.log(err);
71 | } else {
72 | // 处理请求成功
73 | console.log(data.Response);
74 | }
75 | }
76 | );
77 | }
78 |
79 | function setRefer() {
80 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
81 | const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?hotlink';
82 | const url = 'https://' + host;
83 | const body = COS.util.json2xml({
84 | Hotlink: {
85 | Url: 'https://www.example.com', // 必须,域名地址
86 | Type: 'white', // 必须,防盗链类型,white 为白名单,black 为黑名单,off 为关闭。
87 | },
88 | });
89 | cos.request(
90 | {
91 | Method: 'PUT',
92 | Url: url,
93 | Body: body,
94 | },
95 | function (err, data) {
96 | console.log(err || data);
97 | }
98 | );
99 | }
100 |
101 | module.exports = otherDao;
102 |
--------------------------------------------------------------------------------
/demo/demo-post-policy.js:
--------------------------------------------------------------------------------
1 | var config = require('./config');
2 |
3 | var uploadFile = function () {
4 | // 对更多字符编码的 url encode 格式
5 | var camSafeUrlEncode = function (str) {
6 | return encodeURIComponent(str)
7 | .replace(/!/g, '%21')
8 | .replace(/'/g, '%27')
9 | .replace(/\(/g, '%28')
10 | .replace(/\)/g, '%29')
11 | .replace(/\*/g, '%2A');
12 | };
13 |
14 | // 获取临时密钥
15 | var getCredentials = function (options, callback) {
16 | wx.request({
17 | method: 'GET',
18 | url: 'http://127.0.0.1:3000/post-policy?ext=' + options.ext, // 服务端签名,参考 server 目录下的两个签名例子
19 | dataType: 'json',
20 | success: function (result) {
21 | var data = result.data;
22 | if (data) {
23 | callback(data);
24 | } else {
25 | wx.showModal({ title: '临时密钥获取失败', content: JSON.stringify(data), showCancel: false });
26 | }
27 | },
28 | error: function (err) {
29 | wx.showModal({ title: '临时密钥获取失败', content: JSON.stringify(err), showCancel: false });
30 | },
31 | });
32 | };
33 |
34 | // 上传文件
35 | var uploadFile = function (filePath) {
36 | var extIndex = filePath.lastIndexOf('.');
37 | var fileExt = extIndex >= -1 ? filePath.substr(extIndex + 1) : '';
38 | getCredentials({ ext: fileExt }, function (credentials) {
39 | // 请求用到的参数
40 | // var prefix = 'https://cos.' + config.Region + '.myqcloud.com/' + config.Bucket + '/'; // 这个是后缀式,签名也要指定 Pathname: '/' + config.Bucket + '/'
41 | var prefix = 'https://' + credentials.bucket + '.cos.' + credentials.region + '.myqcloud.com/';
42 | var key = credentials.key; // 让服务端来决定文件名更安全
43 | var formData = {
44 | key: key,
45 | success_action_status: 200,
46 | 'Content-Type': '',
47 | 'q-sign-algorithm': credentials.qSignAlgorithm,
48 | 'q-ak': credentials.qAk,
49 | 'q-key-time': credentials.qKeyTime,
50 | 'q-signature': credentials.qSignature,
51 | policy: credentials.policy,
52 | };
53 | if (credentials.securityToken) formData['x-cos-security-token'] = credentials.securityToken;
54 | var requestTask = wx.uploadFile({
55 | url: prefix,
56 | name: 'file',
57 | filePath: filePath,
58 | formData: formData,
59 | success: function (res) {
60 | var url = prefix + camSafeUrlEncode(key).replace(/%2F/g, '/');
61 | if (res.statusCode === 200) {
62 | wx.showModal({ title: '上传成功', content: url, showCancel: false });
63 | } else {
64 | wx.showModal({ title: '上传失败', content: JSON.stringify(res), showCancel: false });
65 | }
66 | console.log(res.header['x-cos-request-id']);
67 | console.log(res.statusCode);
68 | console.log(url);
69 | },
70 | fail: function (res) {
71 | wx.showModal({ title: '上传失败', content: JSON.stringify(res), showCancel: false });
72 | },
73 | });
74 | requestTask.onProgressUpdate(function (res) {
75 | console.log('正在进度:', res);
76 | });
77 | });
78 | };
79 |
80 | // 选择文件
81 | wx.chooseMedia({
82 | count: 1, // 默认9
83 | mediaType: ['image', 'video'],
84 | sizeType: ['original'],
85 | sourceType: ['album', 'camera'],
86 | success: function (res) {
87 | uploadFile(res.tempFiles[0].tempFilePath);
88 | },
89 | });
90 | };
91 |
92 | module.exports = uploadFile;
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 快速入门
2 |
3 | 微信小程序 SDK for [腾讯云对象存储服务](https://cloud.tencent.com/product/cos)
4 |
5 | ### 一、前期准备
6 |
7 | 1. 到 (COS对象存储控制台)[https://console.cloud.tencent.com/cos4] 创建存储桶,得到 Bucket(存储桶名称) 和 Region(地域名称)
8 | 2. 到 (控制台密钥管理)[https://console.cloud.tencent.com/capi] 获取您的项目 SecretId 和 SecretKey
9 |
10 | ### 二、计算签名
11 |
12 | 由于签名计算放在前端会暴露 SecretId 和 SecretKey,我们把签名计算过程放在后端实现,前端通过 ajax 向后端获取签名结果,正式部署时请再后端加一层自己网站本身的权限检验。
13 |
14 | 这里提供 [NodeJS 的签名示例](https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/),其他语言,请参照对应的 [XML SDK](https://cloud.tencent.com/document/product/436/6474)
15 |
16 | ### 三、上传例子
17 |
18 | 1. 把 demo/lib/cos-wx-sdk-v5.js 复制到自己小程序项目代码里,在需要上传文件的地方贴以下代码
19 |
20 | ```javascript
21 | // 存储桶名称,由bucketname-appid 组成,appid必须填入,可以在COS控制台查看存储桶名称。 https://console.cloud.tencent.com/cos5/bucket
22 | const Bucket = 'test-1250000000';
23 | // 存储桶Region可以在COS控制台指定存储桶的概览页查看 https://console.cloud.tencent.com/cos5/bucket/
24 | // 关于地域的详情见 https://cloud.tencent.com/document/product/436/6224
25 | const Region = 'ap-guangzhou';
26 |
27 | // 初始化实例
28 | const cos = new COS({
29 | SimpleUploadMethod: 'putObject', // 强烈建议,高级上传、批量上传内部对小文件做简单上传时使用putObject,sdk版本至少需要v1.3.0
30 | getAuthorization: function (options, callback) {
31 | // 初始化时不会调用,只有调用 cos 方法(例如 cos.putObject)时才会进入
32 | // 异步获取临时密钥
33 | // 服务端 JS 示例:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
34 | // 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
35 | // STS 详细文档指引看:https://cloud.tencent.com/document/product/436/14048
36 | wx.request({
37 | url: 'https://example.com/server/sts', // url 替换成您自己的后端服务
38 | data: {
39 | bucket: options.Bucket,
40 | region: options.Region,
41 | },
42 | dataType: 'json',
43 | success: function (result) {
44 | const data = result.data;
45 | const credentials = data && data.credentials;
46 | if (!data || !credentials) return console.error('credentials invalid');
47 | // 检查credentials格式
48 | console.log(credentials);
49 | callback({
50 | TmpSecretId: credentials.tmpSecretId,
51 | TmpSecretKey: credentials.tmpSecretKey,
52 | // v1.2.0之前版本的 SDK 使用 XCosSecurityToken 而不是 SecurityToken
53 | SecurityToken: credentials.sessionToken,
54 | // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
55 | StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
56 | ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
57 | });
58 | },
59 | });
60 | },
61 | });
62 |
63 | // 选择文件
64 | wx.chooseMedia({
65 | count: 1, // 默认9
66 | mediaType: ['image', 'video'],
67 | sizeType: ['original'],
68 | sourceType: ['album', 'camera'],
69 | success: function (res) {
70 | const filePath = res.tempFiles[0].tempFilePath;
71 | const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
72 | cos.postObject(
73 | {
74 | Bucket: Bucket,
75 | Region: Region,
76 | Key: filename,
77 | FilePath: filePath,
78 | onProgress: function (info) {
79 | console.log(JSON.stringify(info));
80 | },
81 | },
82 | function (err, data) {
83 | console.log(err || data);
84 | }
85 | );
86 | },
87 | });
88 | ```
89 |
90 | ## 说明文档
91 |
92 | [使用例子](demo/demo-sdk.js)
93 |
94 | [快速入门](https://cloud.tencent.com/document/product/436/31953)
95 |
96 | [接口文档](https://cloud.tencent.com/document/product/436/31953)
97 |
--------------------------------------------------------------------------------
/src/session.js:
--------------------------------------------------------------------------------
1 | var util = require('./util');
2 |
3 | // 按照文件特征值,缓存 UploadId
4 | var cacheKey = 'cos_sdk_upload_cache';
5 | var expires = 30 * 24 * 3600;
6 | var cache;
7 | var timer;
8 |
9 | var getCache = function () {
10 | try {
11 | var val = JSON.parse(wx.getStorageSync(cacheKey));
12 | } catch (e) {}
13 | if (!val) val = [];
14 | return val;
15 | };
16 | var setCache = function () {
17 | try {
18 | if (cache.length) wx.setStorageSync(cacheKey, JSON.stringify(cache));
19 | else wx.removeStorageSync(cacheKey);
20 | } catch (e) {}
21 | };
22 |
23 | var init = function () {
24 | if (cache) return;
25 | cache = getCache();
26 | // 清理太老旧的数据
27 | var changed = false;
28 | var now = Math.round(Date.now() / 1000);
29 | for (var i = cache.length - 1; i >= 0; i--) {
30 | var mtime = cache[i][2];
31 | if (!mtime || mtime + expires < now) {
32 | cache.splice(i, 1);
33 | changed = true;
34 | }
35 | }
36 | changed && setCache();
37 | };
38 |
39 | // 把缓存存到本地
40 | var save = function () {
41 | if (timer) return;
42 | timer = setTimeout(function () {
43 | setCache();
44 | timer = null;
45 | }, 400);
46 | };
47 |
48 | var mod = {
49 | using: {},
50 | // 标记 UploadId 正在使用
51 | setUsing: function (uuid) {
52 | mod.using[uuid] = true;
53 | },
54 | // 标记 UploadId 已经没在使用
55 | removeUsing: function (uuid) {
56 | delete mod.using[uuid];
57 | },
58 | // 用上传参数生成哈希值
59 | getFileId: function (FileStat, ChunkSize, Bucket, Key) {
60 | if (FileStat.FilePath && FileStat.size && FileStat.lastModifiedTime && ChunkSize) {
61 | return (
62 | util.md5([FileStat.FilePath].join('::')) +
63 | '-' +
64 | util.md5(
65 | [
66 | FileStat.size,
67 | FileStat.mode,
68 | FileStat.lastAccessedTime,
69 | FileStat.lastModifiedTime,
70 | ChunkSize,
71 | Bucket,
72 | Key,
73 | ].join('::')
74 | )
75 | );
76 | } else {
77 | return null;
78 | }
79 | },
80 | // 用上传参数生成哈希值
81 | getCopyFileId: function (copySource, sourceHeaders, ChunkSize, Bucket, Key) {
82 | var size = sourceHeaders['content-length'];
83 | var etag = sourceHeaders.etag || '';
84 | var lastModified = sourceHeaders['last-modified'];
85 | if (copySource && ChunkSize) {
86 | return util.md5([copySource, size, etag, lastModified, ChunkSize, Bucket, Key].join('::'));
87 | } else {
88 | return null;
89 | }
90 | },
91 | // 获取文件对应的 UploadId 列表
92 | getUploadIdList: function (uuid) {
93 | if (!uuid) return null;
94 | init();
95 | var list = [];
96 | for (var i = 0; i < cache.length; i++) {
97 | if (cache[i][0] === uuid) list.push(cache[i][1]);
98 | }
99 | return list.length ? list : null;
100 | },
101 | // 缓存 UploadId
102 | saveUploadId: function (uuid, UploadId, limit) {
103 | init();
104 | if (!uuid) return;
105 | // 清理没用的 UploadId
106 | var part1 = uuid.substr(0, uuid.indexOf('-') + 1);
107 | for (var i = cache.length - 1; i >= 0; i--) {
108 | var item = cache[i];
109 | if (item[0] === uuid && item[1] === UploadId) {
110 | cache.splice(i, 1);
111 | } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) {
112 | // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉
113 | cache.splice(i, 1);
114 | }
115 | }
116 | cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]);
117 | if (cache.length > limit) cache.splice(limit);
118 | save();
119 | },
120 | // UploadId 已用完,移除掉
121 | removeUploadId: function (UploadId) {
122 | init();
123 | delete mod.using[UploadId];
124 | for (var i = cache.length - 1; i >= 0; i--) {
125 | if (cache[i][1] === UploadId) cache.splice(i, 1);
126 | }
127 | save();
128 | },
129 | };
130 |
131 | module.exports = mod;
132 |
--------------------------------------------------------------------------------
/src/cos.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('./util');
4 | var event = require('./event');
5 | var task = require('./task');
6 | var base = require('./base');
7 | var advance = require('./advance');
8 | var pkg = require('../package.json');
9 |
10 | var defaultOptions = {
11 | SecretId: '',
12 | SecretKey: '',
13 | SecurityToken: '', // 使用临时密钥需要注意自行刷新 Token
14 | StartTime: 0, // 临时密钥返回起始时间
15 | ExpiredTime: 0, // 临时密钥过期时间
16 | ChunkRetryTimes: 2,
17 | FileParallelLimit: 3,
18 | ChunkParallelLimit: 3,
19 | ChunkSize: 1024 * 1024,
20 | SliceSize: 1024 * 1024,
21 | CopyChunkParallelLimit: 20,
22 | CopyChunkSize: 1024 * 1024 * 10,
23 | CopySliceSize: 1024 * 1024 * 10,
24 | MaxPartNumber: 10000,
25 | ProgressInterval: 1000,
26 | UploadQueueSize: 10000,
27 | Domain: '',
28 | ServiceDomain: '',
29 | Protocol: '',
30 | CompatibilityMode: false,
31 | ForcePathStyle: false,
32 | Timeout: 0, // 单位毫秒,0 代表不设置超时时间
33 | CorrectClockSkew: true,
34 | SystemClockOffset: 0, // 单位毫秒,ms
35 | UploadCheckContentMd5: false,
36 | UploadAddMetaMd5: false,
37 | UploadIdCacheLimit: 50,
38 | UseAccelerate: false,
39 | ForceSignHost: true, // 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true
40 | HttpDNSServiceId: '', // HttpDNS 服务商 Id,填写后代表开启 HttpDNS 服务。HttpDNS 用法详见https://developers.weixin.qq.com/miniprogram/dev/framework/ability/HTTPDNS.html
41 | SimpleUploadMethod: 'postObject', // 高级上传内部判断需要走简单上传时,指定的上传方法,可选postObject或putObject
42 | AutoSwitchHost: false,
43 | CopySourceParser: null, // 自定义拷贝源解析器
44 | ObjectKeySimplifyCheck: true, // 开启合并校验 getObject Key
45 | /** 上报相关配置 **/
46 | DeepTracker: false, // 上报时是否对每个分块上传做单独上报
47 | TrackerDelay: 5000, // 周期性上报,单位毫秒。0代表实时上报
48 | CustomId: '', // 自定义上报id
49 | BeaconReporter: null, // 灯塔上报组件,如有需要请自行传入,传入即代表开启上报
50 | ClsReporter: null, // cls 上报组件,如有需要请自行传入,传入即代表开启上报
51 | };
52 |
53 | // 对外暴露的类
54 | var COS = function (options) {
55 | this.options = util.extend(util.clone(defaultOptions), options || {});
56 | this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit);
57 | this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit);
58 | this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes);
59 | this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize);
60 | this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit);
61 | this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize);
62 | this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize);
63 | this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber));
64 | this.options.Timeout = Math.max(0, this.options.Timeout);
65 | this.options.EnableReporter = this.options.BeaconReporter || this.options.ClsReporter;
66 | if (this.options.AppId) {
67 | console.warn(
68 | 'warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'
69 | );
70 | }
71 | if (this.options.SecretId && this.options.SecretId.indexOf(' ') > -1) {
72 | console.error('error: SecretId格式错误,请检查');
73 | console.error('error: SecretId format is incorrect. Please check');
74 | }
75 | if (this.options.SecretKey && this.options.SecretKey.indexOf(' ') > -1) {
76 | console.error('error: SecretKey格式错误,请检查');
77 | console.error('error: SecretKey format is incorrect. Please check');
78 | }
79 | if (this.options.ForcePathStyle) {
80 | console.warn(
81 | 'cos-wx-sdk-v5不再支持使用path-style,仅支持使用virtual-hosted-style,参考文档:https://cloud.tencent.com/document/product/436/96243'
82 | );
83 | throw new Error('ForcePathStyle is not supported');
84 | }
85 | event.init(this);
86 | task.init(this);
87 | };
88 |
89 | base.init(COS, task);
90 | advance.init(COS, task);
91 |
92 | COS.util = {
93 | md5: util.md5,
94 | xml2json: util.xml2json,
95 | json2xml: util.json2xml,
96 | encodeBase64: util.encodeBase64,
97 | };
98 | COS.getAuthorization = util.getAuth;
99 | COS.version = pkg.version;
100 |
101 | module.exports = COS;
102 |
--------------------------------------------------------------------------------
/lib/request.js:
--------------------------------------------------------------------------------
1 | function camSafeUrlEncode(str) {
2 | return encodeURIComponent(str)
3 | .replace(/!/g, '%21')
4 | .replace(/'/g, '%27')
5 | .replace(/\(/g, '%28')
6 | .replace(/\)/g, '%29')
7 | .replace(/\*/g, '%2A');
8 | }
9 |
10 | function getObjectKeys(obj, forKey) {
11 | var list = [];
12 | for (var key in obj) {
13 | if (obj.hasOwnProperty(key)) {
14 | list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key);
15 | }
16 | }
17 | return list.sort(function (a, b) {
18 | a = a.toLowerCase();
19 | b = b.toLowerCase();
20 | return a === b ? 0 : (a > b ? 1 : -1);
21 | });
22 | };
23 |
24 | var obj2str = function (obj, lowerCaseKey) {
25 | var i, key, val;
26 | var list = [];
27 | var keyList = getObjectKeys(obj);
28 | for (i = 0; i < keyList.length; i++) {
29 | key = keyList[i];
30 | val = (obj[key] === undefined || obj[key] === null) ? '' : ('' + obj[key]);
31 | key = lowerCaseKey ? camSafeUrlEncode(key).toLowerCase() : camSafeUrlEncode(key);
32 | val = camSafeUrlEncode(val) || '';
33 | list.push(key + '=' + val)
34 | }
35 | return list.join('&');
36 | };
37 |
38 | var request = function (params, callback) {
39 | var filePath = params.filePath;
40 | var headers = params.headers || {};
41 | var url = params.url || params.Url;
42 | var method = params.method;
43 | var onProgress = params.onProgress;
44 | var httpDNSServiceId = params.httpDNSServiceId;
45 | var requestTask;
46 |
47 | var cb = function (err, response) {
48 | var H = response.header
49 | var headers = {};
50 | if (H) for (var key in H) {
51 | if (H.hasOwnProperty(key)) headers[key.toLowerCase()] = H[key];
52 | }
53 | callback(err, { statusCode: response.statusCode, headers: headers }, response.data);
54 | };
55 |
56 | if (filePath) {
57 | var fileKey;
58 | var m = url.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/);
59 | if (params.pathStyle) {
60 | fileKey = decodeURIComponent(m[3] || '');
61 | url = m[1] + m[2];
62 | } else {
63 | fileKey = decodeURIComponent(m[2] + m[3] || '');
64 | url = m[1];
65 | }
66 |
67 | // 整理 postObject 参数
68 | var formData = {
69 | 'key': fileKey,
70 | 'success_action_status': 200,
71 | 'Signature': headers.Authorization,
72 | };
73 | var headerKeys = [
74 | 'Cache-Control',
75 | 'Content-Type',
76 | 'Content-Disposition',
77 | 'Content-Encoding',
78 | 'Expires',
79 | 'x-cos-storage-class',
80 | 'x-cos-security-token',
81 | 'x-ci-security-token',
82 | ];
83 | for (var i in params.headers) {
84 | if (params.headers.hasOwnProperty(i) && (i.indexOf('x-cos-meta-') > -1 || headerKeys.indexOf(i) > -1)) {
85 | formData[i] = params.headers[i];
86 | }
87 | }
88 | headers['x-cos-acl'] && (formData.acl = headers['x-cos-acl']);
89 | !formData['Content-Type'] && (formData['Content-Type'] = '');
90 |
91 | requestTask = wx.uploadFile({
92 | url: url,
93 | method: method,
94 | name: 'file',
95 | header: headers,
96 | filePath: filePath,
97 | formData: formData,
98 | timeout: params.timeout,
99 | success: function (response) {
100 | cb(null, response);
101 | },
102 | fail: function (response) {
103 | cb(response.errMsg, response);
104 | }
105 | });
106 | requestTask.onProgressUpdate(function (res) {
107 | onProgress && onProgress({
108 | loaded: res.totalBytesSent,
109 | total: res.totalBytesExpectedToSend,
110 | progress: res.progress / 100
111 | });
112 | });
113 | } else {
114 | var qsStr = params.qs && obj2str(params.qs) || '';
115 | if (qsStr) {
116 | url += (url.indexOf('?') > -1 ? '&' : '?') + qsStr;
117 | }
118 | headers['Content-Length'] && (delete headers['Content-Length']);
119 | var requestParams = {
120 | url: url,
121 | method: method,
122 | header: headers,
123 | dataType: 'text',
124 | data: params.body,
125 | responseType: params.dataType || 'text',
126 | timeout: params.timeout,
127 | redirect: 'manual',
128 | success: function (response) {
129 | cb(null, response);
130 | },
131 | fail: function (response) {
132 | cb(response.errMsg, response);
133 | }
134 | };
135 | if (httpDNSServiceId) {
136 | Object.assign(requestParams, {
137 | enableHttpDNS: true,
138 | httpDNSServiceId: httpDNSServiceId,
139 | });
140 | }
141 | requestTask = wx.request(requestParams);
142 | }
143 |
144 | return requestTask;
145 | };
146 |
147 | module.exports = request;
148 |
--------------------------------------------------------------------------------
/demo/tools.js:
--------------------------------------------------------------------------------
1 | var COS = require('./lib/cos-wx-sdk-v5');
2 | var config = require('./config');
3 | const Beacon = require('./lib/beacon_mp.min');
4 | const ClsClient = require('./lib/cls.min');
5 | const clsClient = new ClsClient({
6 | topicId: 'xxxxxx-xxxx-xxxx-xxxx-xxxxxx', // 日志主题 id
7 | region: 'ap-guangzhou', // 日志主题所在地域,比如 ap-guangzhou,需在小程序平台设置域名白名单:https://ap-guangzhou.cls.tencentcs.com
8 | maxRetainDuration: 30, // 默认 30s
9 | maxRetainSize: 20, // 默认20条
10 | });
11 |
12 | // 签名回调
13 | var getAuthorization = function (options, callback) {
14 | // 格式一、(推荐)后端通过获取临时密钥给到前端,前端计算签名
15 | // 服务端 JS 和 PHP 例子:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
16 | // 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
17 | wx.request({
18 | method: 'GET',
19 | url: config.stsUrl, // 服务端签名,参考 server 目录下的两个签名例子
20 | dataType: 'json',
21 | success: function (result) {
22 | var data = result.data;
23 | var credentials = data && data.credentials;
24 | if (!data || !credentials) return console.error('credentials invalid');
25 | callback({
26 | TmpSecretId: credentials.tmpSecretId,
27 | TmpSecretKey: credentials.tmpSecretKey,
28 | SecurityToken: credentials.sessionToken,
29 | StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
30 | ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
31 | });
32 | },
33 | });
34 |
35 | // // 格式二、(推荐)【细粒度控制权限】后端通过获取临时密钥给到前端,前端只有相同请求才重复使用临时密钥,后端可以通过 Scope 细粒度控制权限
36 | // // 服务端例子:https://github.com/tencentyun/qcloud-cos-sts-sdk/edit/master/scope.md
37 | // wx.request({
38 | // method: 'POST',
39 | // url: 'http://127.0.0.1:3000/sts-scope',
40 | // data: options.Scope,
41 | // dataType: 'json',
42 | // success: function(result) {
43 | // var data = result.data;
44 | // var credentials = data && data.credentials;
45 | // if (!data || !credentials) return console.error('credentials invalid');
46 | // callback({
47 | // TmpSecretId: credentials.tmpSecretId,
48 | // TmpSecretKey: credentials.tmpSecretKey,
49 | // XCosSecurityToken: credentials.sessionToken,
50 | // StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
51 | // ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
52 | // ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
53 | // });
54 | // }
55 | // });
56 |
57 | // // 格式三、(不推荐,分片上传权限不好控制)前端每次请求前都需要通过 getAuthorization 获取签名,后端使用固定密钥或临时密钥计算签名返回给前端
58 | // // 服务端获取签名,请参考对应语言的 COS SDK:https://cloud.tencent.com/document/product/436/6474
59 | // // 注意:这种有安全风险,后端需要通过 method、pathname 严格控制好权限,比如不允许 put / 等
60 | // wx.request({
61 | // method: 'POST',
62 | // url: 'https://example.com/sts-auth.php, // 服务端签名,参考 server 目录下的两个签名例子
63 | // data: {
64 | // method: options.Method,
65 | // pathname: options.Pathname,
66 | // query: options.Query,
67 | // headers: options.Headers,
68 | // },
69 | // dataType: 'json',
70 | // success: function(result) {
71 | // var data = result.data;
72 | // if (!data || !data.authorization) return console.error('authorization invalid');
73 | // callback({
74 | // Authorization: data.authorization,
75 | // // XCosSecurityToken: data.sessionToken, // 如果使用临时密钥,需要传 sessionToken
76 | // });
77 | // }
78 | // });
79 |
80 | // // 格式四、(不推荐,适用于前端调试,避免泄露密钥)前端使用固定密钥计算签名
81 | // var authorization = COS.getAuthorization({
82 | // SecretId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
83 | // SecretKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
84 | // Method: options.Method,
85 | // Pathname: options.Pathname,
86 | // Query: options.Query,
87 | // Headers: options.Headers,
88 | // Expires: 60,
89 | // });
90 | // callback({
91 | // Authorization: authorization,
92 | // // XCosSecurityToken: credentials.sessionToken, // 如果使用临时密钥,需要传 XCosSecurityToken
93 | // });
94 | };
95 |
96 | var cos = new COS({
97 | getAuthorization: getAuthorization,
98 | // 是否使用全球加速域名。开启该配置后仅以下接口支持操作:putObject、getObject、headObject、optionsObject、multipartInit、multipartListPart、multipartUpload、multipartAbort、multipartComplete、multipartList、sliceUploadFile、uploadFiles
99 | // UseAccelerate: true,
100 | // BeaconReporter: Beacon, // 开启灯塔上报
101 | // ClsReporter: clsClient, // 开启 cls 上报
102 | });
103 |
104 | // 回调统一处理函数
105 | var requestCallback = function (err, data) {
106 | console.log(err || data);
107 | if (err && err.error) {
108 | wx.showModal({
109 | title: '返回错误',
110 | content: '请求失败:' + (err.error.Message || err.error) + ';状态码:' + err.statusCode,
111 | showCancel: false,
112 | });
113 | } else if (err) {
114 | wx.showModal({
115 | title: '请求出错',
116 | content: '请求出错:' + err + ';状态码:' + err.statusCode,
117 | showCancel: false,
118 | });
119 | } else {
120 | wx.showToast({
121 | title: '请求成功',
122 | icon: 'success',
123 | duration: 3000,
124 | });
125 | }
126 | };
127 |
128 | module.exports = {
129 | cos,
130 | requestCallback,
131 | };
--------------------------------------------------------------------------------
/lib/base64.js:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id: base64.js,v 2.15 2014/04/05 12:58:57 dankogai Exp dankogai $
3 | *
4 | * Licensed under the BSD 3-Clause License.
5 | * http://opensource.org/licenses/BSD-3-Clause
6 | *
7 | * References:
8 | * http://en.wikipedia.org/wiki/Base64
9 | */
10 |
11 | var Base64 = (function(global) {
12 | global = global || {};
13 | 'use strict';
14 | // existing version for noConflict()
15 | var _Base64 = global.Base64;
16 | var version = "2.1.9";
17 | // if node.js, we use Buffer
18 | var buffer;
19 | // constants
20 | var b64chars
21 | = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
22 | var b64tab = function(bin) {
23 | var t = {};
24 | for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
25 | return t;
26 | }(b64chars);
27 | var fromCharCode = String.fromCharCode;
28 | // encoder stuff
29 | var cb_utob = function(c) {
30 | if (c.length < 2) {
31 | var cc = c.charCodeAt(0);
32 | return cc < 0x80 ? c
33 | : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6))
34 | + fromCharCode(0x80 | (cc & 0x3f)))
35 | : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f))
36 | + fromCharCode(0x80 | ((cc >>> 6) & 0x3f))
37 | + fromCharCode(0x80 | ( cc & 0x3f)));
38 | } else {
39 | var cc = 0x10000
40 | + (c.charCodeAt(0) - 0xD800) * 0x400
41 | + (c.charCodeAt(1) - 0xDC00);
42 | return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07))
43 | + fromCharCode(0x80 | ((cc >>> 12) & 0x3f))
44 | + fromCharCode(0x80 | ((cc >>> 6) & 0x3f))
45 | + fromCharCode(0x80 | ( cc & 0x3f)));
46 | }
47 | };
48 | var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
49 | var utob = function(u) {
50 | return u.replace(re_utob, cb_utob);
51 | };
52 | var cb_encode = function(ccc) {
53 | var padlen = [0, 2, 1][ccc.length % 3],
54 | ord = ccc.charCodeAt(0) << 16
55 | | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8)
56 | | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),
57 | chars = [
58 | b64chars.charAt( ord >>> 18),
59 | b64chars.charAt((ord >>> 12) & 63),
60 | padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63),
61 | padlen >= 1 ? '=' : b64chars.charAt(ord & 63)
62 | ];
63 | return chars.join('');
64 | };
65 | var btoa = global.btoa ? function(b) {
66 | return global.btoa(b);
67 | } : function(b) {
68 | return b.replace(/[\s\S]{1,3}/g, cb_encode);
69 | };
70 | var _encode = buffer ? function (u) {
71 | return (u.constructor === buffer.constructor ? u : new buffer(u))
72 | .toString('base64')
73 | }
74 | : function (u) { return btoa(utob(u)) }
75 | ;
76 | var encode = function(u, urisafe) {
77 | return !urisafe
78 | ? _encode(String(u))
79 | : _encode(String(u)).replace(/[+\/]/g, function(m0) {
80 | return m0 == '+' ? '-' : '_';
81 | }).replace(/=/g, '');
82 | };
83 | var encodeURI = function(u) { return encode(u, true) };
84 | // decoder stuff
85 | var re_btou = new RegExp([
86 | '[\xC0-\xDF][\x80-\xBF]',
87 | '[\xE0-\xEF][\x80-\xBF]{2}',
88 | '[\xF0-\xF7][\x80-\xBF]{3}'
89 | ].join('|'), 'g');
90 | var cb_btou = function(cccc) {
91 | switch(cccc.length) {
92 | case 4:
93 | var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
94 | | ((0x3f & cccc.charCodeAt(1)) << 12)
95 | | ((0x3f & cccc.charCodeAt(2)) << 6)
96 | | (0x3f & cccc.charCodeAt(3)),
97 | offset = cp - 0x10000;
98 | return (fromCharCode((offset >>> 10) + 0xD800)
99 | + fromCharCode((offset & 0x3FF) + 0xDC00));
100 | case 3:
101 | return fromCharCode(
102 | ((0x0f & cccc.charCodeAt(0)) << 12)
103 | | ((0x3f & cccc.charCodeAt(1)) << 6)
104 | | (0x3f & cccc.charCodeAt(2))
105 | );
106 | default:
107 | return fromCharCode(
108 | ((0x1f & cccc.charCodeAt(0)) << 6)
109 | | (0x3f & cccc.charCodeAt(1))
110 | );
111 | }
112 | };
113 | var btou = function(b) {
114 | return b.replace(re_btou, cb_btou);
115 | };
116 | var cb_decode = function(cccc) {
117 | var len = cccc.length,
118 | padlen = len % 4,
119 | n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0)
120 | | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0)
121 | | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0)
122 | | (len > 3 ? b64tab[cccc.charAt(3)] : 0),
123 | chars = [
124 | fromCharCode( n >>> 16),
125 | fromCharCode((n >>> 8) & 0xff),
126 | fromCharCode( n & 0xff)
127 | ];
128 | chars.length -= [0, 0, 2, 1][padlen];
129 | return chars.join('');
130 | };
131 | var atob = global.atob ? function(a) {
132 | return global.atob(a);
133 | } : function(a){
134 | return a.replace(/[\s\S]{1,4}/g, cb_decode);
135 | };
136 | var _decode = buffer ? function(a) {
137 | return (a.constructor === buffer.constructor
138 | ? a : new buffer(a, 'base64')).toString();
139 | }
140 | : function(a) { return btou(atob(a)) };
141 | var decode = function(a){
142 | return _decode(
143 | String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' })
144 | .replace(/[^A-Za-z0-9\+\/]/g, '')
145 | );
146 | };
147 | var noConflict = function() {
148 | var Base64 = global.Base64;
149 | global.Base64 = _Base64;
150 | return Base64;
151 | };
152 | // export Base64
153 | var Base64 = {
154 | VERSION: version,
155 | atob: atob,
156 | btoa: btoa,
157 | fromBase64: decode,
158 | toBase64: encode,
159 | utob: utob,
160 | encode: encode,
161 | encodeURI: encodeURI,
162 | btou: btou,
163 | decode: decode,
164 | noConflict: noConflict
165 | };
166 | return Base64;
167 | })();
168 |
169 | module.exports = Base64;
170 |
171 |
--------------------------------------------------------------------------------
/demo/lib/cos-auth.js:
--------------------------------------------------------------------------------
1 | !function(){"use strict";function t(t){return encodeURIComponent(t).replace(/!/g,"%21").replace(/'/g,"%27").replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/\*/g,"%2A")}var e=e||function(t,e){var n={},r=n.lib={},i=function(){},s=r.Base={extend:function(t){i.prototype=this;var e=new i;return t&&e.mixIn(t),e.hasOwnProperty("init")||(e.init=function(){e.$super.init.apply(this,arguments)}),e.init.prototype=e,e.$super=this,e},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}},o=r.WordArray=s.extend({init:function(t,e){t=this.words=t||[],this.sigBytes=void 0!=e?e:4*t.length},toString:function(t){return(t||c).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes;if(t=t.sigBytes,this.clamp(),r%4)for(var i=0;i>>2]|=(n[i>>>2]>>>24-i%4*8&255)<<24-(r+i)%4*8;else if(65535>>2]=n[i>>>2];else e.push.apply(e,n);return this.sigBytes+=t,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=s.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n=[],r=0;r>>2]>>>24-r%4*8&255;n.push((i>>>4).toString(16)),n.push((15&i).toString(16))}return n.join("")},parse:function(t){for(var e=t.length,n=[],r=0;r>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new o.init(n,e/2)}},h=a.Latin1={stringify:function(t){var e=t.words;t=t.sigBytes;for(var n=[],r=0;r>>2]>>>24-r%4*8&255));return n.join("")},parse:function(t){for(var e=t.length,n=[],r=0;r>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new o.init(n,e)}},u=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(h.stringify(t)))}catch(t){throw Error("Malformed UTF-8 data")}},parse:function(t){return h.parse(unescape(encodeURIComponent(t)))}},f=r.BufferedBlockAlgorithm=s.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=u.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,i=n.sigBytes,s=this.blockSize,a=i/(4*s),a=e?t.ceil(a):t.max((0|a)-this._minBufferSize,0);if(e=a*s,i=t.min(4*e,i),e){for(var c=0;ch;h++){if(16>h)s[h]=0|t[e+h];else{var u=s[h-3]^s[h-8]^s[h-14]^s[h-16];s[h]=u<<1|u>>>31}u=(r<<5|r>>>27)+c+s[h],u=20>h?u+(1518500249+(i&o|~i&a)):40>h?u+(1859775393+(i^o^a)):60>h?u+((i&o|i&a|o&a)-1894007588):u+((i^o^a)-899497514),c=a,a=o,o=i<<30|i>>>2,i=r,r=u}n[0]=n[0]+r|0,n[1]=n[1]+i|0,n[2]=n[2]+o|0,n[3]=n[3]+a|0,n[4]=n[4]+c|0},_doFinalize:function(){var t=this._data,e=t.words,n=8*this._nDataBytes,r=8*t.sigBytes;return e[r>>>5]|=128<<24-r%32,e[14+(r+64>>>9<<4)]=Math.floor(n/4294967296),e[15+(r+64>>>9<<4)]=n,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}});t.SHA1=i._createHelper(n),t.HmacSHA1=i._createHmacHelper(n)}(),function(){var t=e,n=t.enc.Utf8;t.algo.HMAC=t.lib.Base.extend({init:function(t,e){t=this._hasher=new t.init,"string"==typeof e&&(e=n.parse(e));var r=t.blockSize,i=4*r;e.sigBytes>i&&(e=t.finalize(e)),e.clamp();for(var s=this._oKey=e.clone(),o=this._iKey=e.clone(),a=s.words,c=o.words,h=0;h>>2]>>>24-s%4*8&255,a=e[s+1>>>2]>>>24-(s+1)%4*8&255,c=e[s+2>>>2]>>>24-(s+2)%4*8&255,h=o<<16|a<<8|c,u=0;u<4&&s+.75*u>>6*(3-u)&63));var f=r.charAt(64);if(f)for(;i.length%4;)i.push(f);return i.join("")},parse:function(t){var e=t.length,n=this._map,i=n.charAt(64);if(i){var s=t.indexOf(i);-1!=s&&(e=s)}for(var o=[],a=0,c=0;c>>6-c%4*2;o[a>>>2]|=(h|u)<<24-a%4*8,a++}return r.create(o,a)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}();var n=function(t){var n=t.Pathname||"/",r=t.Expires,i="",s="",o=t.Bucket.match(/^(.+)-(\d+)$/);o&&(i=o[1],s=o[2]);var a=parseInt(Math.random()*Math.pow(2,32)),c=parseInt(Date.now()/1e3),h=c+(void 0===r?900:1*r||0),u="/"+s+"/"+i+encodeURIComponent(n).replace(/%2F/g,"/"),f="a="+s+"&b="+i+"&k="+t.SecretId+"&e="+h+"&t="+c+"&r="+a+"&f="+u,l=e.HmacSHA1(f,t.SecretKey),p=e.enc.Utf8.parse(f);return l.concat(p).toString(e.enc.Base64)},r=function(r){if(!r.SecretId)return console.error("missing param SecretId");if(!r.SecretKey)return console.error("missing param SecretKey");if("4.0"===r.Version)return n(r);r=r||{};var i=r.SecretId,s=r.SecretKey,o=(r.Method||"get").toLowerCase(),a=r.Query||{},c=r.Headers||{},h=r.Pathname||"/",u=r.Expires,f=function(t){var e=[];for(var n in t)t.hasOwnProperty(n)&&e.push(n);return e.sort(function(t,e){return t=t.toLowerCase(),e=e.toLowerCase(),t===e?0:t>e?1:-1})},l=function(e){var n,r,i,s=[],o=f(e);for(n=0;n ('000000' + x).slice(-(n || 2));
43 | var d = new Date();
44 | var ymd = d.getFullYear() + N(d.getMonth() + 1) + N(d.getDate());
45 | var hms = N(d.getHours()) + N(d.getMinutes()) + N(d.getSeconds());
46 | var r = N(Math.round((Math.random() * 1000000)), 6);
47 | var fileName = ymd + '_' + hms + '_' + r;
48 | if (ext) fileName += '.' + ext;
49 | return fileName;
50 | };
51 |
52 | // 创建临时密钥服务
53 | var app = express();
54 | app.use(bodyParser.json());
55 |
56 | // 格式一:临时密钥接口
57 | app.all('/sts', function (req, res, next) {
58 |
59 | // TODO 这里根据自己业务需要做好放行判断
60 | if (config.allowPrefix === '_ALLOW_DIR_/*') {
61 | res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
62 | return;
63 | }
64 |
65 | // 获取临时密钥
66 | var LongBucketName = config.bucket;
67 | var ShortBucketName = LongBucketName.substr(0, LongBucketName.lastIndexOf('-'));
68 | var AppId = LongBucketName.substr(LongBucketName.lastIndexOf('-') + 1);
69 | var policy = {
70 | 'version': '2.0',
71 | 'statement': [{
72 | 'action': config.allowActions,
73 | 'effect': 'allow',
74 | 'resource': [
75 | 'qcs::cos:' + config.region + ':uid/' + AppId + ':prefix//' + AppId + '/' + ShortBucketName + '/' + config.allowPrefix,
76 | ],
77 | }],
78 | };
79 | var startTime = Math.round(Date.now() / 1000);
80 | STS.getCredential({
81 | secretId: config.secretId,
82 | secretKey: config.secretKey,
83 | proxy: config.proxy,
84 | region: config.region,
85 | durationSeconds: config.durationSeconds,
86 | policy: policy,
87 | }, function (err, tempKeys) {
88 | if (tempKeys) tempKeys.startTime = startTime;
89 | res.send(err || tempKeys);
90 | });
91 | });
92 |
93 |
94 | // // 格式二:临时密钥接口,支持细粒度权限控制
95 | // // 判断是否允许获取密钥
96 | // var allowScope = function (scope) {
97 | // var allow = (scope || []).every(function (item) {
98 | // return config.allowActions.includes(item.action) &&
99 | // item.bucket === config.bucket &&
100 | // item.region === config.region &&
101 | // (item.prefix || '').startsWith(config.allowPrefix);
102 | // });
103 | // return allow;
104 | // };
105 | // app.all('/sts-scope', function (req, res, next) {
106 | // var scope = req.body;
107 | //
108 | // // TODO 这里根据自己业务需要做好放行判断
109 | // if (config.allowPrefix === '_ALLOW_DIR_/*') {
110 | // res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
111 | // return;
112 | // }
113 | // // TODO 这里可以判断 scope 细粒度控制权限
114 | // if (!scope || !scope.length || !allowScope(scope)) return res.send({error: 'deny'});
115 | //
116 | // // 获取临时密钥
117 | // var policy = STS.getPolicy(scope);
118 | // var startTime = Math.round(Date.now() / 1000);
119 | // STS.getCredential({
120 | // secretId: config.secretId,
121 | // secretKey: config.secretKey,
122 | // proxy: config.proxy,
123 | // durationSeconds: config.durationSeconds,
124 | // policy: policy,
125 | // }, function (err, tempKeys) {
126 | // if (tempKeys) tempKeys.startTime = startTime;
127 | // res.send(err || tempKeys);
128 | // });
129 | // });
130 | //
131 | // // 用于 PostObject 签名保护
132 | // app.all('/post-policy', function (req, res, next) {
133 | // var query = req.query;
134 | // var ext = query.ext;
135 | // var key = 'images/' + createFileName(ext);
136 | // var now = Math.round(Date.now() / 1000);
137 | // var exp = now + 900;
138 | // var qKeyTime = now + ';' + exp;
139 | // var qSignAlgorithm = 'sha1';
140 | // var policy = JSON.stringify({
141 | // 'expiration': new Date(exp * 1000).toISOString(),
142 | // 'conditions': [
143 | // // {'acl': query.ACL},
144 | // // ['starts-with', '$Content-Type', 'image/'],
145 | // // ['starts-with', '$success_action_redirect', redirectUrl],
146 | // // ['eq', '$x-cos-server-side-encryption', 'AES256'],
147 | // {'q-sign-algorithm': qSignAlgorithm},
148 | // {'q-ak': config.secretId},
149 | // {'q-sign-time': qKeyTime},
150 | // {'bucket': config.bucket},
151 | // {'key': key},
152 | // ]
153 | // });
154 | //
155 | // // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
156 | // // 步骤一:生成 SignKey
157 | // var signKey = crypto.createHmac('sha1', config.secretKey).update(qKeyTime).digest('hex');
158 | //
159 | // // 步骤二:生成 StringToSign
160 | // var stringToSign = crypto.createHash('sha1').update(policy).digest('hex');
161 | //
162 | // // 步骤三:生成 Signature
163 | // var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex');
164 | //
165 | // console.log(policy);
166 | // res.send({
167 | // bucket: config.bucket,
168 | // region: config.region,
169 | // key: key,
170 | // policyObj: JSON.parse(policy),
171 | // policy: Buffer.from(policy).toString('base64'),
172 | // qSignAlgorithm: qSignAlgorithm,
173 | // qAk: config.secretId,
174 | // qKeyTime: qKeyTime,
175 | // qSignature: qSignature,
176 | // // securityToken: securityToken, // 如果使用临时密钥,要返回在这个资源 sessionToken 的值
177 | // });
178 | // });
179 |
180 | app.all('*', function (req, res, next) {
181 | res.send({code: -1, message: '404 Not Found'});
182 | });
183 |
184 | // 启动签名服务
185 | app.listen(3000);
186 | console.log('app is listening at http://127.0.0.1:3000');
187 |
--------------------------------------------------------------------------------
/demo/ciDemo/audit.js:
--------------------------------------------------------------------------------
1 | const COS = require('../lib/cos-wx-sdk-v5');
2 | const config = require('../config');
3 | const { cos, requestCallback } = require('../tools');
4 |
5 | const auditDao = {
6 | '图片同步审核 getImageAuditing': getImageAuditing,
7 | '图片批量审核 postImagesAuditing': postImagesAuditing,
8 | '查询图片审核任务结果 getImageAuditingResult': getImageAuditingResult,
9 | '提交视频审核任务 postVideoAuditing': postVideoAuditing,
10 | '查询视频审核任务结果 getVideoAuditingResult': getVideoAuditingResult,
11 | '提交音频审核任务 postAudioAuditing': postAudioAuditing,
12 | '查询音频审核任务结果 getAudioAuditingResult': getAudioAuditingResult,
13 | '提交文本审核任务 postTextAuditing': postTextAuditing,
14 | '提交直播审核任务 postLiveAuditing': postLiveAuditing,
15 | '查询直播审核任务结果 getLiveAuditingResult': getLiveAuditingResult,
16 | };
17 |
18 | function getImageAuditing() {
19 | cos.request(
20 | {
21 | Bucket: config.Bucket,
22 | Region: config.Region,
23 | Method: 'GET',
24 | Key: '1.png',
25 | Query: {
26 | 'ci-process': 'sensitive-content-recognition' /** 固定值,必须 */,
27 | 'biz-type': '' /** 审核类型,非必须 */,
28 | 'detect-url': '' /** 审核任意公网可访问的图片链接,非必须,与Key二选一传递 */,
29 | interval: 5 /** 审核 GIF 动图时,每隔interval帧截取一帧,非必须 */,
30 | 'max-frames': 5 /** 审核 GIF 动图时,最大截帧数,非必须 */,
31 | 'large-image-detect': '0' /** 是否需要压缩图片后再审核,非必须 */,
32 | },
33 | },
34 | function (err, data) {
35 | console.log(err || data);
36 | }
37 | );
38 | }
39 |
40 | function postImagesAuditing() {
41 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
42 | var url = 'https://' + host + '/image/auditing';
43 | var body = COS.util.json2xml({
44 | Request: {
45 | Input: [
46 | {
47 | Object: '1.png',
48 | },
49 | {
50 | Object: '6.png',
51 | },
52 | ],
53 | Conf: {
54 | BizType: '',
55 | },
56 | },
57 | });
58 | cos.request(
59 | {
60 | Bucket: config.Bucket,
61 | Region: config.Region,
62 | Method: 'POST',
63 | Url: url,
64 | Key: '/image/auditing',
65 | ContentType: 'application/xml',
66 | Body: body,
67 | },
68 | function (err, data) {
69 | console.log(err || data);
70 | }
71 | );
72 | }
73 |
74 | function getImageAuditingResult() {
75 | var jobId = 'si8263213daf3711eca0d1525400d88xxx'; // jobId可以通过图片批量审核返回
76 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
77 | var url = 'https://' + host + '/image/auditing/' + jobId;
78 | cos.request(
79 | {
80 | Bucket: config.Bucket,
81 | Region: config.Region,
82 | Method: 'GET',
83 | Key: '/image/auditing/' + jobId,
84 | Url: url,
85 | },
86 | function (err, data) {
87 | console.log(err || data);
88 | }
89 | );
90 | }
91 |
92 | function postVideoAuditing() {
93 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
94 | var url = 'https://' + host + '/video/auditing';
95 | var body = COS.util.json2xml({
96 | Request: {
97 | Input: {
98 | Object: '1.mp4',
99 | },
100 | Conf: {
101 | BizType: '',
102 | Snapshot: {
103 | Count: 1000, // 视频截帧数量
104 | },
105 | DetectContent: 1, // 是否审核视频声音,0-只审核视频不审核声音;1-审核视频+声音
106 | },
107 | },
108 | });
109 | cos.request(
110 | {
111 | Bucket: config.Bucket,
112 | Region: config.Region,
113 | Method: 'POST',
114 | Url: url,
115 | Key: '/video/auditing',
116 | ContentType: 'application/xml',
117 | Body: body,
118 | },
119 | function (err, data) {
120 | console.log(err || data);
121 | }
122 | );
123 | }
124 |
125 | function getVideoAuditingResult() {
126 | var jobId = 'av5bd873d9f39011ecb6c95254009a49da'; // jobId可以通过提交视频审核任务返回
127 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
128 | var url = 'https://' + host + '/video/auditing/' + jobId;
129 | cos.request(
130 | {
131 | Bucket: config.Bucket,
132 | Region: config.Region,
133 | Method: 'GET',
134 | Key: '/video/auditing/' + jobId,
135 | Url: url,
136 | },
137 | function (err, data) {
138 | console.log(err || data);
139 | }
140 | );
141 | }
142 |
143 | function postAudioAuditing() {
144 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
145 | var url = 'https://' + host + '/audio/auditing';
146 | var body = COS.util.json2xml({
147 | Request: {
148 | Input: {
149 | Object: '1.mp3',
150 | },
151 | Conf: {
152 | BizType: '',
153 | },
154 | },
155 | });
156 | cos.request(
157 | {
158 | Bucket: config.Bucket,
159 | Region: config.Region,
160 | Method: 'POST',
161 | Url: url,
162 | Key: '/audio/auditing',
163 | ContentType: 'application/xml',
164 | Body: body,
165 | },
166 | function (err, data) {
167 | console.log(err || data);
168 | }
169 | );
170 | }
171 |
172 | function getAudioAuditingResult() {
173 | var jobId = 'sa0c28d41daff411ecb23352540078cxxx'; // jobId可以通过提交音频审核任务返回
174 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
175 | var url = 'https://' + host + '/audio/auditing/' + jobId;
176 | cos.request(
177 | {
178 | Bucket: config.Bucket,
179 | Region: config.Region,
180 | Method: 'GET',
181 | Key: '/audio/auditing/' + jobId,
182 | Url: url,
183 | },
184 | function (err, data) {
185 | console.log(err || data);
186 | }
187 | );
188 | }
189 |
190 | function postTextAuditing() {
191 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
192 | var url = 'https://' + host + '/text/auditing';
193 | var body = COS.util.json2xml({
194 | Request: {
195 | Input: {
196 | Content: COS.util.encodeBase64('hello') /* 需要审核的文本内容 */,
197 | },
198 | Conf: {
199 | BizType: '',
200 | },
201 | },
202 | });
203 | cos.request(
204 | {
205 | Bucket: config.Bucket,
206 | Region: config.Region,
207 | Method: 'POST',
208 | Url: url,
209 | Key: '/text/auditing' /** 固定值,必须 */,
210 | ContentType: 'application/xml' /** 固定值,必须 */,
211 | Body: body,
212 | },
213 | function (err, data) {
214 | console.log(err || data);
215 | }
216 | );
217 | }
218 |
219 | function postLiveAuditing() {
220 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
221 | var url = 'https://' + host + '/video/auditing';
222 | var body = COS.util.json2xml({
223 | Request: {
224 | Type: 'live_video',
225 | Input: {
226 | Url: 'rtmp://example.com/live/123', // 需要审核的直播流播放地址
227 | // DataId: '',
228 | // UserInfo: {},
229 | },
230 | Conf: {
231 | BizType: '',
232 | // Callback: 'https://callback.com', // 回调地址,非必须
233 | // CallbackType: 1, // 回调片段类型,非必须
234 | },
235 | },
236 | });
237 | cos.request(
238 | {
239 | Bucket: config.Bucket,
240 | Region: config.Region,
241 | Method: 'POST',
242 | Url: url,
243 | Key: '/video/auditing',
244 | ContentType: 'application/xml',
245 | Body: body,
246 | },
247 | function (err, data) {
248 | console.log(err || data);
249 | }
250 | );
251 | }
252 |
253 | function getLiveAuditingResult() {
254 | var jobId = 'av2b14a74dbd9011edb05a52540084c0xx'; // jobId可以通过提交直播审核任务返回
255 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
256 | var url = 'https://' + host + '/video/auditing/' + jobId;
257 | cos.request(
258 | {
259 | Bucket: config.Bucket,
260 | Region: config.Region,
261 | Method: 'GET',
262 | Key: '/video/auditing/' + jobId,
263 | Url: url,
264 | },
265 | function (err, data) {
266 | console.log(err || data);
267 | }
268 | );
269 | }
270 |
271 | module.exports = auditDao;
272 |
--------------------------------------------------------------------------------
/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 | module.exports = CryptoJS;
125 |
--------------------------------------------------------------------------------
/demo/ciDemo/asr.js:
--------------------------------------------------------------------------------
1 | const COS = require('../lib/cos-wx-sdk-v5');
2 | const config = require('../config');
3 | const { cos, requestCallback } = require('../tools');
4 |
5 | const asrDao = {
6 | '提交音频降噪任务 postNoiseReduction': postNoiseReduction,
7 | '提交人声分离任务 postVoiceSeparate': postVoiceSeparate,
8 | '提交语音合成任务 postTts': postTts,
9 | '提交语音识别任务 postSpeechRecognition': postSpeechRecognition,
10 | '查询语音识别队列 getAsrQueue': getAsrQueue,
11 | '更新语音识别队列 putAsrQueue': putAsrQueue,
12 | '查询语音识别开通状态 getAsrBucket': getAsrBucket,
13 | };
14 |
15 | function postNoiseReduction() {
16 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/jobs';
17 | var url = 'https://' + host;
18 | var body = COS.util.json2xml({
19 | Request: {
20 | Tag: 'NoiseReduction',
21 | Input: {
22 | Object: 'ci/music.mp3', // 文件名,取值为文件在当前存储桶中的完整名称
23 | },
24 | Operation: {
25 | Output: {
26 | Bucket: config.Bucket, // 输出的存储桶
27 | Region: config.Region, // 输出的存储桶的地域
28 | Object: 'ci/out.mp3', // 输出的文件Key
29 | },
30 | },
31 | // QueueId: '', // 任务所在的队列 ID,非必须
32 | // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须
33 | // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须
34 | // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须
35 | // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须
36 | },
37 | });
38 | cos.request(
39 | {
40 | Method: 'POST',
41 | Key: 'jobs',
42 | Url: url,
43 | Body: body,
44 | ContentType: 'application/xml',
45 | },
46 | function (err, data) {
47 | console.log(err || data);
48 | }
49 | );
50 | }
51 |
52 | function postVoiceSeparate() {
53 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/jobs';
54 | var url = 'https://' + host;
55 | var body = COS.util.json2xml({
56 | Request: {
57 | Tag: 'VoiceSeparate',
58 | Input: {
59 | Object: 'ci/music.mp3', // 文件名,取值为文件在当前存储桶中的完整名称
60 | },
61 | Operation: {
62 | // VoiceSeparate: {}, // 指定转码模板参数,非必须
63 | TemplateId: 't13fca82ad97e84878a22cd81bd2e5652c', // 指定的模板 ID,必须
64 | // JobLevel: 0, // 任务优先级,级别限制:0 、1 、2。级别越大任务优先级越高,默认为0,非必须
65 | Output: {
66 | Bucket: config.Bucket, // 输出的存储桶
67 | Region: config.Region, // 输出的存储桶的地域
68 | Object: 'ci/out/background.mp3', // 输出的文件Key,背景音结果文件名,不能与 AuObject 同时为空
69 | AuObject: 'ci/out/audio.mp3',
70 | },
71 | },
72 | // QueueId: '', // 任务所在的队列 ID,非必须
73 | // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须
74 | // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须
75 | // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须
76 | // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须
77 | },
78 | });
79 | cos.request(
80 | {
81 | Method: 'POST',
82 | Key: 'jobs',
83 | Url: url,
84 | Body: body,
85 | ContentType: 'application/xml',
86 | },
87 | function (err, data) {
88 | console.log(err || data);
89 | }
90 | );
91 | }
92 |
93 | function postTts() {
94 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/jobs';
95 | var url = 'https://' + host;
96 | var body = COS.util.json2xml({
97 | Request: {
98 | Tag: 'Tts',
99 | Operation: {
100 | // VoiceSeparate: {}, // 指定转码模板参数,非必须
101 | TemplateId: 't192931b3564084168a3f50ebfea59acb3', // 指定的模板 ID,必须
102 | // JobLevel: 0, // 任务优先级,级别限制:0 、1 、2。级别越大任务优先级越高,默认为0,非必须
103 | TtsConfig: {
104 | InputType: 'Text',
105 | Input: '床前明月光,疑是地上霜',
106 | },
107 | Output: {
108 | Bucket: config.Bucket, // 输出的存储桶
109 | Region: config.Region, // 输出的存储桶的地域
110 | Object: 'ci/out/tts.mp3', // 输出的文件Key
111 | },
112 | },
113 | // QueueId: '', // 任务所在的队列 ID,非必须
114 | // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须
115 | // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须
116 | // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须
117 | // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须
118 | },
119 | });
120 | cos.request(
121 | {
122 | Method: 'POST',
123 | Key: 'jobs',
124 | Url: url,
125 | Body: body,
126 | ContentType: 'application/xml',
127 | },
128 | function (err, data) {
129 | console.log(err || data);
130 | }
131 | );
132 | }
133 |
134 | function postSpeechRecognition() {
135 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/asr_jobs';
136 | var url = 'https://' + host;
137 | var body = COS.util.json2xml({
138 | Request: {
139 | Tag: 'SpeechRecognition',
140 | Input: {
141 | Object: 'ci/music.mp3', // 文件名,取值为文件在当前存储桶中的完整名称,与Url参数二选一
142 | // Url: 'http://examplebucket-1250000000.cos.ap-shanghai.myqcloud.com/music.mp3', // 病毒文件的链接地址,与Object参数二选一
143 | },
144 | Operation: {
145 | SpeechRecognition: {
146 | EngineModelType: '16k_zh_video', // 引擎模型类型
147 | ChannelNum: 1, // 语音声道数
148 | ResTextFormat: 0, // 识别结果返回形式
149 | FilterDirty: 1, // 是否过滤脏词(目前支持中文普通话引擎)
150 | FilterModal: 1, // 是否过语气词(目前支持中文普通话引擎)
151 | ConvertNumMode: 0, // 是否进行阿拉伯数字智能转换(目前支持中文普通话引擎)
152 | },
153 | Output: {
154 | Bucket: config.Bucket, // 输出的存储桶
155 | Region: config.Region, // 输出的存储桶的地域
156 | Object: 'ci/out/SpeechRecognition.mp3', // 输出的文件Key
157 | },
158 | },
159 | // QueueId: '', // 任务所在的队列 ID,非必须
160 | // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须
161 | // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须
162 | // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须
163 | // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须
164 | },
165 | });
166 | cos.request(
167 | {
168 | Method: 'POST',
169 | Key: 'asr_jobs',
170 | Url: url,
171 | Body: body,
172 | ContentType: 'application/xml',
173 | },
174 | function (err, data) {
175 | console.log(err || data);
176 | }
177 | );
178 | }
179 |
180 | function getAsrQueue() {
181 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/asrqueue';
182 | var url = 'https://' + host;
183 | cos.request(
184 | {
185 | Method: 'GET',
186 | Key: 'asrqueue',
187 | Url: url,
188 | Query: {
189 | // queueIds: '', /* 非必须,队列 ID,以“,”符号分割字符串 */
190 | // state: '', /* 非必须,1=Active,2=Paused */
191 | // pageNumber: 1, /* 非必须,第几页 */
192 | // pageSize: 2, /* 非必须,每页个数 */
193 | },
194 | },
195 | function (err, data) {
196 | console.log(err || data);
197 | }
198 | );
199 | }
200 |
201 | function putAsrQueue() {
202 | // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46234)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询
203 | var queueId = 'pcc77499e85c311edb9865254008618d9';
204 | var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/asrqueue/' + queueId;
205 | var url = 'https://' + host;
206 | var body = COS.util.json2xml({
207 | Request: {
208 | Name: 'queue-doc-process-1',
209 | QueueID: queueId,
210 | State: 'Paused',
211 | NotifyConfig: {
212 | // Url: '',
213 | // Type: 'Url',
214 | // Event: '',
215 | State: 'Off',
216 | },
217 | },
218 | });
219 | cos.request(
220 | {
221 | Method: 'PUT',
222 | Key: 'asrqueue/' + queueId,
223 | Url: url,
224 | Body: body,
225 | ContentType: 'application/xml',
226 | },
227 | function (err, data) {
228 | console.log(err || data);
229 | }
230 | );
231 | }
232 |
233 | function getAsrBucket() {
234 | var host = 'ci.' + config.Region + '.myqcloud.com/asrbucket';
235 | var url = 'https://' + host;
236 | cos.request(
237 | {
238 | Method: 'GET',
239 | Key: 'asrbucket',
240 | Url: url,
241 | Query: {
242 | // regions: '', /* 非必须,地域信息,以“,”分隔字符串,支持 All、ap-shanghai、ap-beijing */
243 | // bucketNames: '', /* 非必须,存储桶名称,以“,”分隔,支持多个存储桶,精确搜索 */
244 | // bucketName: '', /* 非必须,存储桶名称前缀,前缀搜索 */
245 | // pageNumber: 1, /* 非必须,第几页 */
246 | // pageSize: 10, /* 非必须,每页个数 */
247 | },
248 | },
249 | function (err, data) {
250 | console.log(err || data);
251 | }
252 | );
253 | }
254 |
255 | module.exports = asrDao;
256 |
--------------------------------------------------------------------------------
/src/task.js:
--------------------------------------------------------------------------------
1 | var session = require('./session');
2 | var util = require('./util');
3 |
4 | var originApiMap = {};
5 | var transferToTaskMethod = function (apiMap, apiName) {
6 | originApiMap[apiName] = apiMap[apiName];
7 | apiMap[apiName] = function (params, callback) {
8 | if (params.SkipTask) {
9 | originApiMap[apiName].call(this, params, callback);
10 | } else {
11 | this._addTask(apiName, params, callback);
12 | }
13 | };
14 | };
15 |
16 | var initTask = function (cos) {
17 | var queue = [];
18 | var tasks = {};
19 | var uploadingFileCount = 0;
20 | var nextUploadIndex = 0;
21 |
22 | // 接口返回简略的任务信息
23 | var formatTask = function (task) {
24 | var t = {
25 | id: task.id,
26 | Bucket: task.Bucket,
27 | Region: task.Region,
28 | Key: task.Key,
29 | FilePath: task.FilePath,
30 | state: task.state,
31 | loaded: task.loaded,
32 | size: task.size,
33 | speed: task.speed,
34 | percent: task.percent,
35 | hashPercent: task.hashPercent,
36 | error: task.error,
37 | };
38 | if (task.FilePath) t.FilePath = task.FilePath;
39 | return t;
40 | };
41 |
42 | var emitListUpdate = (function () {
43 | var timer;
44 | var emit = function () {
45 | timer = 0;
46 | cos.emit('task-list-update', { list: util.map(queue, formatTask) });
47 | cos.emit('list-update', { list: util.map(queue, formatTask) });
48 | };
49 | return function () {
50 | if (!timer) timer = setTimeout(emit);
51 | };
52 | })();
53 |
54 | var clearQueue = function () {
55 | if (queue.length <= cos.options.UploadQueueSize) return;
56 | for (
57 | var i = 0;
58 | i < nextUploadIndex && // 小于当前操作的 index 才清理
59 | i < queue.length && // 大于队列才清理
60 | queue.length > cos.options.UploadQueueSize; // 如果还太多,才继续清理
61 |
62 | ) {
63 | var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading';
64 | if (!queue[i] || !isActive) {
65 | tasks[queue[i].id] && delete tasks[queue[i].id];
66 | queue.splice(i, 1);
67 | nextUploadIndex--;
68 | } else {
69 | i++;
70 | }
71 | }
72 | emitListUpdate();
73 | };
74 |
75 | var startNextTask = function () {
76 | // 检查是否允许增加执行进程
77 | if (uploadingFileCount >= cos.options.FileParallelLimit) return;
78 | // 跳过不可执行的任务
79 | while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++;
80 | // 检查是否已遍历结束
81 | if (nextUploadIndex >= queue.length) return;
82 | // 上传该遍历到的任务
83 | var task = queue[nextUploadIndex];
84 | nextUploadIndex++;
85 | uploadingFileCount++;
86 | task.state = 'checking';
87 | task.params.onTaskStart && task.params.onTaskStart(formatTask(task));
88 | !task.params.UploadData && (task.params.UploadData = {});
89 | var apiParams = util.formatParams(task.api, task.params);
90 | originApiMap[task.api].call(cos, apiParams, function (err, data) {
91 | if (!cos._isRunningTask(task.id)) return;
92 | if (task.state === 'checking' || task.state === 'uploading') {
93 | task.state = err ? 'error' : 'success';
94 | err && (task.error = err);
95 | uploadingFileCount--;
96 | emitListUpdate();
97 | startNextTask();
98 | task.callback && task.callback(err, data);
99 | if (task.state === 'success') {
100 | if (task.params) {
101 | delete task.params.UploadData;
102 | delete task.params.Body;
103 | delete task.params;
104 | }
105 | delete task.callback;
106 | }
107 | }
108 | clearQueue();
109 | });
110 | emitListUpdate();
111 | // 异步执行下一个任务
112 | setTimeout(startNextTask);
113 | };
114 |
115 | var killTask = function (id, switchToState) {
116 | var task = tasks[id];
117 | if (!task) return;
118 | var waiting = task && task.state === 'waiting';
119 | var running = task && (task.state === 'checking' || task.state === 'uploading');
120 | if (
121 | (switchToState === 'canceled' && task.state !== 'canceled') ||
122 | (switchToState === 'paused' && waiting) ||
123 | (switchToState === 'paused' && running)
124 | ) {
125 | if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') {
126 | console.error('stream not support pause');
127 | return;
128 | }
129 | task.state = switchToState;
130 | cos.emit('inner-kill-task', { TaskId: id, toState: switchToState });
131 | try {
132 | var UploadId = task && task.params && task.params.UploadData.UploadId;
133 | } catch (e) {}
134 | if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId);
135 | emitListUpdate();
136 | if (running) {
137 | uploadingFileCount--;
138 | startNextTask();
139 | }
140 | if (switchToState === 'canceled') {
141 | if (task.params) {
142 | delete task.params.UploadData;
143 | delete task.params.Body;
144 | delete task.params;
145 | }
146 | delete task.callback;
147 | }
148 | }
149 | clearQueue();
150 | };
151 |
152 | cos._addTasks = function (taskList) {
153 | util.each(taskList, function (task) {
154 | cos._addTask(task.api, task.params, task.callback, true);
155 | });
156 | emitListUpdate();
157 | };
158 |
159 | cos._addTask = function (api, params, callback, ignoreAddEvent) {
160 | // 如果小程序版本不支持获取文件分片内容,统一转到 简单上传 接口上传
161 | var simpleUploadMethod = cos.options.SimpleUploadMethod === 'postObject' ? 'postObject' : 'putObject';
162 | if (api === 'sliceUploadFile' && !util.canFileSlice()) api = simpleUploadMethod;
163 |
164 | // 复制参数对象
165 | params = util.formatParams(api, params);
166 |
167 | // 生成 id
168 | var id = util.uuid();
169 | params.TaskId = id;
170 | params.onTaskReady && params.onTaskReady(id);
171 |
172 | var task = {
173 | // env
174 | params: params,
175 | callback: callback,
176 | api: api,
177 | index: queue.length,
178 | // task
179 | id: id,
180 | Bucket: params.Bucket,
181 | Region: params.Region,
182 | Key: params.Key,
183 | FilePath: params.FilePath || '',
184 | state: 'waiting',
185 | loaded: 0,
186 | size: 0,
187 | speed: 0,
188 | percent: 0,
189 | hashPercent: 0,
190 | error: null,
191 | };
192 | var onHashProgress = params.onHashProgress;
193 | params.onHashProgress = function (info) {
194 | if (!cos._isRunningTask(task.id)) return;
195 | task.hashPercent = info.percent;
196 | onHashProgress && onHashProgress(info);
197 | emitListUpdate();
198 | };
199 | var onProgress = params.onProgress;
200 | params.onProgress = function (info) {
201 | if (!cos._isRunningTask(task.id)) return;
202 | task.state === 'checking' && (task.state = 'uploading');
203 | task.loaded = info.loaded;
204 | task.size = info.total;
205 | task.speed = info.speed;
206 | task.percent = info.percent;
207 | onProgress && onProgress(info);
208 | emitListUpdate();
209 | };
210 |
211 | // 异步获取 filesize
212 | util.getFileSize(api, params, function (err, size) {
213 | // 开始处理上传
214 | if (err) {
215 | // 如果获取大小出错,不加入队列
216 | callback(err);
217 | return;
218 | }
219 | // 获取完文件大小再把任务加入队列
220 | tasks[id] = task;
221 | queue.push(task);
222 | task.size = size;
223 | !ignoreAddEvent && emitListUpdate();
224 | startNextTask();
225 | clearQueue();
226 | });
227 | return id;
228 | };
229 | cos._isRunningTask = function (id) {
230 | var task = tasks[id];
231 | return !!(task && (task.state === 'checking' || task.state === 'uploading'));
232 | };
233 | cos.getTaskList = function () {
234 | return util.map(queue, formatTask);
235 | };
236 | cos.cancelTask = function (id) {
237 | killTask(id, 'canceled');
238 | };
239 | cos.pauseTask = function (id) {
240 | killTask(id, 'paused');
241 | };
242 | cos.restartTask = function (id) {
243 | var task = tasks[id];
244 | if (task && (task.state === 'paused' || task.state === 'error')) {
245 | task.state = 'waiting';
246 | emitListUpdate();
247 | nextUploadIndex = Math.min(nextUploadIndex, task.index);
248 | startNextTask();
249 | }
250 | };
251 | cos.isUploadRunning = function () {
252 | return uploadingFileCount || nextUploadIndex < queue.length;
253 | };
254 | };
255 |
256 | module.exports.transferToTaskMethod = transferToTaskMethod;
257 | module.exports.init = initTask;
258 |
--------------------------------------------------------------------------------
/demo-album/pages/album/album.js:
--------------------------------------------------------------------------------
1 | const { listToMatrix } = require('../../lib/util.js');
2 | var COS = require('../../lib/cos-wx-sdk-v5.js');
3 | const config = require('../../config.js');
4 | const util = require('../../lib/util.js');
5 |
6 |
7 | var cos = new COS({
8 | getAuthorization: function (options, callback) {
9 | wx.request({
10 | method: 'GET',
11 | url: config.stsUrl, // 服务端签名,参考 server 目录下的两个签名例子
12 | dataType: 'json',
13 | success: function (result) {
14 | var data = result.data;
15 | callback({
16 | TmpSecretId: data.credentials && data.credentials.tmpSecretId,
17 | TmpSecretKey: data.credentials && data.credentials.tmpSecretKey,
18 | XCosSecurityToken: data.credentials && data.credentials.sessionToken,
19 | ExpiredTime: data.expiredTime,
20 | });
21 | }
22 | });
23 | },
24 | });
25 |
26 | Page({
27 | data: {
28 | // 相册列表数据
29 | albumList: [],
30 |
31 | // 图片布局列表(二维数组,由`albumList`计算而得)
32 | layoutList: [],
33 |
34 | // 布局列数
35 | layoutColumnSize: 3,
36 |
37 | // 是否显示loading
38 | showLoading: false,
39 |
40 | // loading提示语
41 | loadingMessage: '',
42 |
43 | // 是否显示toast
44 | showToast: false,
45 |
46 | // 提示消息
47 | toastMessage: '',
48 |
49 | // 是否显示动作命令
50 | showActionsSheet: false,
51 |
52 | // 当前操作的图片
53 | imageInAction: '',
54 |
55 | // 图片预览模式
56 | previewMode: false,
57 |
58 | // 当前预览索引
59 | previewIndex: 0,
60 |
61 | // 切换动画的时间
62 | slideDuration: 400,
63 | },
64 | onShareAppMessage: function (res) {
65 | return {
66 | title: 'COS 上传示例 - 共享相册',
67 | path: this.route,
68 | }
69 | },
70 |
71 | // 显示loading提示
72 | showLoading(loadingMessage) {
73 | this.setData({ showLoading: true, loadingMessage });
74 | },
75 |
76 | // 隐藏loading提示
77 | hideLoading() {
78 | this.setData({ showLoading: false, loadingMessage: '' });
79 | },
80 |
81 | // 显示toast消息
82 | showToast(toastMessage) {
83 | this.setData({ showToast: true, toastMessage });
84 | },
85 |
86 | // 隐藏toast消息
87 | hideToast() {
88 | this.setData({ showToast: false, toastMessage: '' });
89 | },
90 |
91 | // 隐藏动作列表
92 | hideActionSheet() {
93 | this.setData({ showActionsSheet: false, imageInAction: '' });
94 | },
95 |
96 | onLoad() {
97 | var self = this;
98 | this.renderAlbumList();
99 | this.getAlbumList(function (list) {
100 | list = self.data.albumList.concat(list || {});
101 | if (!list.length) {
102 | list = [];
103 | }
104 | list = list.reverse();
105 | self.setData({ 'albumList': list });
106 | self.renderAlbumList();
107 | });
108 | },
109 |
110 | // 获取相册列表
111 | getAlbumList(callback) {
112 | this.showLoading('加载列表中…');
113 | setTimeout(() => this.hideLoading(), 1000);
114 | cos.getBucket({
115 | Bucket: config.Bucket,
116 | Region: config.Region,
117 | Prefix: config.albumDir
118 | }, function (err, data) {
119 | if (data) {
120 | var list = (data && data.Contents || [])
121 | .map((v) => 'https://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + util.camSafeUrlEncode(v.Key).replace(/%2F/g, '/'))
122 | .filter((v) => /\.(jpg|png|gif)$/.test(v));
123 | callback(list);
124 | } else {
125 | callback([]);
126 | }
127 | });
128 | },
129 |
130 | // 渲染相册列表
131 | renderAlbumList() {
132 | let layoutColumnSize = this.data.layoutColumnSize;
133 | let layoutList = [];
134 | var imageList = [].concat(this.data.albumList);
135 | imageList.unshift({type:'add'});
136 | layoutList = listToMatrix(imageList, layoutColumnSize);
137 | this.setData({ layoutList });
138 | },
139 |
140 | // 从相册选择照片或拍摄照片
141 | chooseImage() {
142 | var self = this;
143 | wx.chooseImage({
144 | count: 9,
145 | sizeType: ['original', 'compressed'],
146 | sourceType: ['album', 'camera'],
147 | success: (res) => {
148 | this.showLoading('正在上传图片…');
149 | res.tempFilePaths.forEach(function (filePath) {
150 | var Key = config.albumDir + util.getRandFileName(filePath);
151 | filePath && cos.postObject({
152 | Bucket: config.Bucket,
153 | Region: config.Region,
154 | Key: Key,
155 | FilePath: filePath
156 | }, function (err, data) {
157 | if (data) {
158 | let albumList = self.data.albumList;
159 | albumList.unshift('https://' + data.Location);
160 | self.setData({ albumList });
161 | self.renderAlbumList();
162 | }
163 | self.hideLoading();
164 | });
165 | });
166 | },
167 | });
168 | },
169 |
170 | // 进入预览模式
171 | enterPreviewMode(event) {
172 | var self = this;
173 | if (this.data.showActionsSheet) {
174 | return;
175 | }
176 | let imageUrl = event.target.dataset.src;
177 | let previewIndex = this.data.albumList.indexOf(imageUrl);
178 |
179 | this.setData({ slideDuration: 0 });
180 | setTimeout(function () {
181 | self.setData({ previewMode: true, previewIndex: previewIndex});
182 | setTimeout(function () {
183 | self.setData({ slideDuration: 400 });
184 | }, 400);
185 | });
186 | },
187 |
188 | // 退出预览模式
189 | leavePreviewMode() {
190 | this.setData({ previewMode: false, previewIndex: 0 });
191 | },
192 |
193 | // 显示可操作命令
194 | showActions(event) {
195 | this.setData({ showActionsSheet: true, imageInAction: event.target.dataset.src });
196 | },
197 |
198 | // 下载图片
199 | downloadImage() {
200 | this.showLoading('正在保存图片…');
201 | console.log('download_image_url', this.data.imageInAction);
202 |
203 | wx.downloadFile({
204 | url: this.data.imageInAction,
205 | type: 'image',
206 | success: (resp) => {
207 | wx.saveFile({
208 | tempFilePath: resp.tempFilePath,
209 | success: (resp) => {
210 | this.showToast('图片保存成功');
211 | },
212 | fail: (resp) => {
213 | console.log('fail', resp);
214 | },
215 | complete: (resp) => {
216 | console.log('complete', resp);
217 | this.hideLoading();
218 | },
219 | });
220 | },
221 |
222 | fail: (resp) => {
223 | console.log('fail', resp);
224 | },
225 | });
226 |
227 | this.setData({ showActionsSheet: false, imageInAction: '' });
228 | },
229 |
230 | // 删除图片
231 | deleteImage() {
232 | let imageUrl = this.data.imageInAction;
233 | var m = imageUrl.match(/^https:\/\/[^\/]+\/([^#?]+)/);
234 | var Key = m && m[1] || '';
235 | if (Key) {
236 | this.showLoading('正在删除图片…');
237 | this.setData({ showActionsSheet: false, imageInAction: '' });
238 | cos.deleteObject({
239 | Bucket: config.Bucket,
240 | Region: config.Region,
241 | Key: Key,
242 | }, (err, data)=>{
243 | if (data) {
244 | let index = this.data.albumList.indexOf(imageUrl);
245 | if (~index) {
246 | let albumList = this.data.albumList;
247 | albumList.splice(index, 1);
248 | this.setData({ albumList });
249 | this.renderAlbumList();
250 | }
251 | this.showToast('图片删除成功');
252 | } else {
253 | this.showToast('图片删除失败');
254 | }
255 | this.hideLoading();
256 | });
257 | }
258 | },
259 | });
260 |
--------------------------------------------------------------------------------
/src/tracker.js:
--------------------------------------------------------------------------------
1 | const pkg = require('../package.json');
2 | let beacon = null;
3 |
4 | const getBeacon = (Beacon, delay) => {
5 | if (!beacon) {
6 | // 生成 beacon
7 | if (typeof Beacon !== 'function') {
8 | throw new Error('Beacon not found');
9 | }
10 | beacon = new Beacon({
11 | appkey: '0WEB05PY6MHRGK0U',
12 | versionCode: pkg.version,
13 | channelID: 'mp_sdk', //渠道,选填
14 | openid: 'openid', // 用户id, 选填
15 | unionid: 'unid', //用户unionid , 类似idfv,选填
16 | strictMode: false, //严苛模式开关, 打开严苛模式会主动抛出异常, 上线请务必关闭!!!
17 | delay, // 普通事件延迟上报时间(单位毫秒), 默认1000(1秒),选填
18 | sessionDuration: 60 * 1000, // session变更的时间间隔, 一个用户持续30分钟(默认值)没有任何上报则算另一次 session,每变更一次session上报一次启动事件(rqd_applaunched),使用毫秒(ms),最小值30秒,选填
19 | });
20 | }
21 | return beacon;
22 | };
23 |
24 | // 毫秒转秒
25 | const ms2s = function (ms) {
26 | if (!ms || ms < 0) return 0;
27 | return (ms / 1000).toFixed(3);
28 | };
29 |
30 | const utils = {
31 | // 生成uid 每个链路对应唯一一条uid
32 | getUid() {
33 | var S4 = function () {
34 | return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
35 | };
36 | return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
37 | },
38 | // 获取网络类型 4g | wifi
39 | getNetType() {
40 | return new Promise((resolve) => {
41 | if (wx.canIUse('getNetworkType')) {
42 | try {
43 | wx.getNetworkType({
44 | success(res) {
45 | resolve(res.networkType);
46 | },
47 | });
48 | } catch (e) {
49 | resolve('can_not_get_network_type');
50 | }
51 | } else {
52 | resolve('can_not_get_network_type');
53 | }
54 | });
55 | },
56 | // 获取系统信息
57 | getSystemInfo() {
58 | const baseInfo = {
59 | // ↓上报项
60 | devicePlatform: 'can_not_get_system_info', // ios/anroid/windows/mac/devtools
61 | wxVersion: 'can_not_get_system_info',
62 | wxSystem: 'can_not_get_system_info',
63 | wxSdkVersion: 'can_not_get_system_info',
64 | };
65 | let appBaseInfo = {};
66 | let deviceInfo = {};
67 | if (wx.canIUse('getAppBaseInfo')) {
68 | appBaseInfo = wx.getAppBaseInfo() || {};
69 | }
70 | if (wx.canIUse('getDeviceInfo')) {
71 | deviceInfo = wx.getDeviceInfo() || {};
72 | }
73 | const sdkVersion = appBaseInfo.SDKVersion || 'can_not_get_system_info';
74 | const version = appBaseInfo.version || 'can_not_get_system_info';
75 | const platform = deviceInfo.platform || 'can_not_get_system_info';
76 | const system = deviceInfo.system || 'can_not_get_system_info';
77 |
78 | Object.assign(baseInfo, {
79 | devicePlatform: platform,
80 | wxVersion: version,
81 | wxSystem: system,
82 | wxSdkVersion: sdkVersion,
83 | });
84 | return baseInfo;
85 | },
86 | };
87 |
88 | // 设备信息,只取一次值
89 | const deviceInfo = utils.getSystemInfo();
90 |
91 | const transApiName = (api) => {
92 | if (['putObject', 'sliceUploadFile', 'uploadFile', 'uploadFiles'].includes(api)) {
93 | return 'UploadTask';
94 | } else if (api === 'getObject') {
95 | return 'DownloadTask';
96 | } else if (['putObjectCopy', 'sliceCopyFile'].includes(api)) {
97 | return 'CopyTask';
98 | }
99 | return api;
100 | };
101 |
102 | // 上报参数驼峰改下划线
103 | function camel2underline(key) {
104 | return key.replace(/([A-Z])/g, '_$1').toLowerCase();
105 | }
106 | function formatParams(params) {
107 | const formattedParams = {};
108 | const successKeys = [
109 | 'sdkVersionName',
110 | 'sdkVersionCode',
111 | 'osName',
112 | 'networkType',
113 | 'requestName',
114 | 'requestResult',
115 | 'bucket',
116 | 'region',
117 | 'appid',
118 | 'accelerate',
119 | 'url',
120 | 'host',
121 | 'requestPath',
122 | 'userAgent',
123 | 'httpMethod',
124 | 'httpSize',
125 | 'httpSpeed',
126 | 'httpTookTime',
127 | 'httpMd5',
128 | 'httpSign',
129 | 'httpFullTime',
130 | 'httpDomain',
131 | 'partNumber',
132 | 'httpRetryTimes',
133 | 'customId',
134 | 'traceId',
135 | 'realApi',
136 | ];
137 | const failureKeys = [
138 | ...successKeys,
139 | 'errorNode',
140 | 'errorCode',
141 | 'errorName',
142 | 'errorMessage',
143 | 'errorRequestId',
144 | 'errorHttpCode',
145 | 'errorServiceName',
146 | 'errorType',
147 | 'fullError',
148 | ];
149 | // 需要上报的参数字段
150 | const reporterKeys = params.requestResult === 'Success' ? successKeys : failureKeys;
151 | for (let key in params) {
152 | if (!reporterKeys.includes(key)) continue;
153 | const formattedKey = camel2underline(key);
154 | formattedParams[formattedKey] = params[key];
155 | }
156 | formattedParams['request_name'] = params.realApi ? transApiName(params.realApi) : params.requestName;
157 | return formattedParams;
158 | }
159 |
160 | // 链路追踪器
161 | class Tracker {
162 | constructor(opt) {
163 | const {
164 | parent,
165 | traceId,
166 | bucket,
167 | region,
168 | apiName,
169 | realApi,
170 | httpMethod,
171 | fileKey,
172 | fileSize,
173 | accelerate,
174 | customId,
175 | delay,
176 | deepTracker,
177 | Beacon,
178 | clsReporter,
179 | } = opt;
180 | const appid = (bucket && bucket.substr(bucket.lastIndexOf('-') + 1)) || '';
181 | this.parent = parent;
182 | this.deepTracker = deepTracker;
183 | this.delay = delay;
184 | if (clsReporter && !this.clsReporter) {
185 | this.clsReporter = clsReporter;
186 | }
187 | // 上报用到的字段
188 | this.params = {
189 | // 通用字段
190 | sdkVersionName: 'cos-wx-sdk-v5',
191 | sdkVersionCode: pkg.version,
192 | osName: deviceInfo.devicePlatform,
193 | networkType: '',
194 |
195 | requestName: apiName || '',
196 | requestResult: '', // sdk api调用结果Success、Failure
197 | realApi,
198 |
199 | bucket,
200 | region,
201 | accelerate,
202 | httpMethod,
203 | url: '',
204 | host: '',
205 | httpDomain: '',
206 | requestPath: fileKey || '',
207 |
208 | errorType: '',
209 | errorCode: '',
210 | errorName: '',
211 | errorMessage: '',
212 | errorRequestId: '',
213 | errorHttpCode: 0,
214 | errorServiceName: '',
215 | errorNode: '',
216 |
217 | httpTookTime: 0, // http整体耗时
218 | httpSize: fileSize || 0, // 主要是文件大小,大小 B
219 | httpMd5: 0, // MD5耗时
220 | httpSign: 0, // 计算签名耗时
221 | httpFullTime: 0, // 任务整体耗时(包括md5、签名等)
222 | httpSpeed: 0, // 主要关注上传速度,KB/s
223 |
224 | size: fileSize || 0,
225 | httpMd5: 0, // MD5耗时
226 | httpSign: 0, // 计算签名耗时
227 | httpFull: 0, // http请求耗时
228 | name: apiName || '',
229 | tookTime: 0, // 总耗时
230 | md5StartTime: 0, // md5计算开始时间
231 | md5EndTime: 0, // md5计算结束时间
232 | signStartTime: 0, // 计算签名开始时间
233 | signEndTime: 0, // 计算签名结束时间
234 | httpStartTime: 0, // 发起网络请求开始时间
235 | httpEndTime: 0, // 网路请求结束时间
236 | startTime: new Date().getTime(), // sdk api调用起始时间,不是纯网络耗时
237 | endTime: 0, // sdk api调用结束时间,不是纯网络耗时
238 |
239 | // 小程序补充字段
240 | traceId: traceId || utils.getUid(), // 每条上报唯一标识
241 | appid,
242 | partNumber: 0, // 分块上传编号
243 | httpRetryTimes: 0, // sdk内部发起的请求重试
244 | customId: customId || '', // 业务id
245 | partTime: 0,
246 | };
247 | if (Beacon) {
248 | this.beacon = getBeacon(Beacon, delay);
249 | }
250 | }
251 |
252 | // 格式化sdk回调
253 | async formatResult(err, data) {
254 | /**
255 | * 解析到err的格式为:
256 | * 1.服务端有返回时
257 | * {
258 | * err: 同下方error,
259 | * error: {
260 | * error: {
261 | * Code: '', Message: '', Resource: '', RequestId: '', TraceId: '',
262 | * },
263 | * statusCode: xxx,
264 | * headers: {},
265 | * RequestId: '',
266 | * },
267 | * }
268 | * 2.本地抛出或小程序直接报错
269 | * {error: 'message'}或{error: {error: 'message' }}
270 | */
271 | const now = new Date().getTime();
272 | const networkType = await utils.getNetType();
273 | const errorCode = err ? err?.error?.error?.Code || 'Error' : '';
274 | const errorMessage = err ? err?.error?.error?.Message || err?.error?.error || err?.error || '' : '';
275 | const errorName = errorMessage;
276 | const errorHttpCode = err ? err?.error?.statusCode : data.statusCode;
277 | const errorServiceName = err ? err?.error?.error?.Resource : '';
278 | const requestId = err ? err?.error?.RequestId || '' : data?.RequestId || '';
279 | const errorType = err ? (requestId ? 'Server' : 'Client') : '';
280 |
281 | if (this.params.requestName === 'getObject') {
282 | this.params.httpSize = data ? data.headers && data.headers['content-length'] : 0;
283 | }
284 |
285 | // 上报 sliceUploadFile || uploadFile || uploadFiles 命中分块上传时
286 | const isSliceUploadFile = this.params.realApi === 'sliceUploadFile';
287 | const isSliceCopyFile = this.params.realApi === 'sliceCopyFile';
288 |
289 | if (isSliceUploadFile || isSliceCopyFile) {
290 | const speed = this.params.httpSize / 1024 / this.params.partTime;
291 | Object.assign(this.params, { httpSpeed: speed < 0 ? 0 : speed.toFixed(3) });
292 | } else {
293 | const httpFullTime = now - this.params.startTime;
294 | const httpTookTime = this.params.httpEndTime - this.params.httpStartTime;
295 | const speed = this.params.httpSize / 1024 / (httpTookTime / 1000);
296 | const httpMd5 = this.params.md5EndTime - this.params.md5StartTime;
297 | const httpSign = this.params.signEndTime - this.params.signStartTime;
298 |
299 | if (this.parent) {
300 | this.parent.addParamValue('httpTookTime', ms2s(httpTookTime));
301 | this.parent.addParamValue('httpFullTime', ms2s(httpFullTime));
302 | this.parent.addParamValue('httpMd5', ms2s(httpMd5));
303 | this.parent.addParamValue('httpSign', ms2s(httpSign));
304 | if (['multipartUpload', 'uploadPartCopy', 'putObjectCopy'].includes(this.params.requestName)) {
305 | // 只有小分块上传|复制才累计纯请求耗时,计算速度时用到
306 | this.parent.addParamValue('partTime', ms2s(httpTookTime));
307 | }
308 | }
309 | Object.assign(this.params, {
310 | httpFullTime: ms2s(httpFullTime),
311 | httpMd5: ms2s(httpMd5),
312 | httpSign: ms2s(httpSign),
313 | httpTookTime: ms2s(httpTookTime),
314 | httpSpeed: speed < 0 ? 0 : speed.toFixed(3),
315 | });
316 | }
317 |
318 | Object.assign(this.params, {
319 | networkType,
320 | requestResult: err ? 'Failure' : 'Success',
321 | errorType,
322 | errorCode,
323 | errorHttpCode,
324 | errorName,
325 | errorMessage,
326 | errorServiceName,
327 | errorRequestId: requestId,
328 | });
329 | if (err && (!errorCode || !errorMessage)) {
330 | // 暂存全量err一段时间 观察是否所有err格式都可被解析
331 | this.params.fullError = err ? JSON.stringify(err) : '';
332 | }
333 | if (this.params.name === 'getObject') {
334 | this.params.size = data ? data.headers && data.headers['content-length'] : -1;
335 | }
336 | if (this.params.url) {
337 | try {
338 | const exec = /^http(s)?:\/\/(.*?)\//.exec(this.params.url);
339 | this.params.host = exec[2];
340 | } catch (e) {
341 | this.params.host = this.params.url;
342 | }
343 | this.params.httpDomain = this.params.host;
344 | }
345 | }
346 |
347 | // 上报
348 | async report(err, data) {
349 | if (!this.beacon && !this.clsReporter) return;
350 | await this.formatResult(err, data);
351 | const formattedParams = formatParams(this.params);
352 | if (this.beacon) {
353 | this.sendEventsToBeacon(formattedParams);
354 | }
355 | if (this.clsReporter) {
356 | this.sendEventsToCLS(formattedParams);
357 | }
358 | }
359 |
360 | // 设置当前链路的参数
361 | setParams(params) {
362 | Object.assign(this.params, params);
363 | }
364 |
365 | addParamValue(key, value) {
366 | this.params[key] = (+this.params[key] + +value).toFixed(3);
367 | }
368 |
369 | // 上报灯塔
370 | sendEventsToBeacon(formattedParams) {
371 | // DeepTracker模式下才会上报分块上传内部细节
372 | const isSliceUploadFile =
373 | this.params.requestName === 'sliceUploadFile' || this.params.realApi === 'sliceUploadFile';
374 | if (isSliceUploadFile && !this.deepTracker) {
375 | return;
376 | }
377 | const eventCode = 'qcloud_track_cos_sdk';
378 |
379 | if (this.delay === 0) {
380 | // 实时上报
381 | this.beacon && this.beacon.onDirectUserAction(eventCode, formattedParams);
382 | } else {
383 | // 周期性上报
384 | this.beacon && this.beacon.onUserAction(eventCode, formattedParams);
385 | }
386 | }
387 |
388 | // 上报 cls
389 | sendEventsToCLS(formattedParams) {
390 | // 是否实时上报
391 | const immediate = !!(this.delay === 0);
392 |
393 | this.clsReporter.log(formattedParams, immediate);
394 | }
395 |
396 | // 生成子实例,与父所属一个链路,可用于分块上传内部流程上报单个分块操作
397 | generateSubTracker(subParams) {
398 | Object.assign(subParams, {
399 | parent: this,
400 | deepTracker: this.deepTracker,
401 | traceId: this.params.traceId,
402 | bucket: this.params.bucket,
403 | region: this.params.region,
404 | accelerate: this.params.accelerate,
405 | fileKey: this.params.requestPath,
406 | customId: this.params.customId,
407 | delay: this.params.delay,
408 | clsReporter: this.clsReporter,
409 | });
410 | return new Tracker(subParams);
411 | }
412 | }
413 |
414 | module.exports = Tracker;
415 |
--------------------------------------------------------------------------------
/demo/ciDemo/docPreview.js:
--------------------------------------------------------------------------------
1 | const COS = require('../lib/cos-wx-sdk-v5');
2 | var wxfs = wx.getFileSystemManager();
3 | const config = require('../config');
4 | const { cos, requestCallback } = require('../tools');
5 |
6 | const docPreviewDao = {
7 | '查询文档预览开通状态 describeDocProcessService': describeDocProcessService,
8 | '文档转html同步请求 getDocHtmlPreviewUrl': getDocHtmlPreviewUrl,
9 | '文档转码同步请求 getDocPreview': getDocPreview,
10 | '提交文档转码任务 createDocProcessJob': createDocProcessJob,
11 | '查询指定文档转码任务 describeDocProcessJob': describeDocProcessJob,
12 | '拉取符合条件的文档转码任务 describeDocProcessJobList': describeDocProcessJobList,
13 | '查询文档转码队列 describeDocProcessQueue': describeDocProcessQueue,
14 | '更新文档转码队列 updateProcessQueue': updateProcessQueue,
15 | };
16 |
17 | function describeDocProcessService() {
18 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
19 | const key = `docbucket`; //
20 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
21 | const url = `https://${host}/${key}`;
22 | cos.request(
23 | {
24 | Method: 'GET', // 固定值,必须
25 | Key: key, // 必须
26 | Url: url, // 请求的url,必须
27 | Query: {
28 | // 地域信息,以“,”分隔字符串,支持 All、ap-shanghai、ap-beijing;是否必传:否
29 | regions: '',
30 | // 存储桶名称,以“,”分隔,支持多个存储桶,精确搜索;是否必传:否
31 | bucketNames: '',
32 | // 存储桶名称前缀,前缀搜索;是否必传:否
33 | bucketName: '',
34 | // 第几页;是否必传:否
35 | pageNumber: '',
36 | // 每页个数;是否必传:否
37 | pageSize: '',
38 | },
39 | },
40 | function (err, data) {
41 | if (err) {
42 | // 处理请求失败
43 | console.log(err);
44 | } else {
45 | // 处理请求成功
46 | console.log(data.Response);
47 | }
48 | }
49 | );
50 | }
51 |
52 | function getDocHtmlPreviewUrl() {
53 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
54 | const ObjectKey = 'test.docx';
55 | const key = `${ObjectKey}`; // ObjectKey:{ObjectKey};
56 | const host = `${config.Bucket}.cos.${config.Region}.myqcloud.com`;
57 | const url = `https://${host}/${key}`;
58 |
59 | cos.request(
60 | {
61 | Method: 'GET', // 固定值,必须
62 | Key: key, // 必须
63 | Url: url, // 请求的url,必须
64 | Query: {
65 | // 数据万象处理能力,文档 HTML 预览固定为 doc-preview;是否必传:是
66 | 'ci-process': 'doc-preview',
67 | // 转换输出目标文件类型,文档 HTML 预览固定为 html(需为小写字母);是否必传:是
68 | dstType: 'html',
69 | // 是否获取预览链接。填入值为1会返回预览链接和Token信息;填入值为2只返回Token信息;不传会直接预览;是否必传:否
70 | weboffice_url: 1,
71 | // 指定目标文件类型,支持的文件类型请见下方;是否必传:否
72 | srcType: '',
73 | // 对象下载签名,如果预览的对象为私有读时,需要传入签名,详情请参见 请求签名 文档注意:需要进行 urlencode;是否必传:否
74 | sign: '',
75 | // 是否可复制。默认为可复制,填入值为1;不可复制,填入值为0;是否必传:否
76 | copyable: '',
77 | // 自定义配置参数,json结构,需要经过 URL 安全 的 Base64 编码,默认配置为:{ commonOptions: { isShowTopArea: true, isShowHeader: true, language: "zh" }},支持的配置参考 自定义配置项说明。htmlParams支持的特殊配置:语言切换,通过 commonOptions 的 language 参数指定预览语言,支持"zh"、"en“,默认为"zh"。;是否必传:否
78 | htmlParams: '',
79 | // 水印文字,需要经过 URL 安全 的 Base64 编码,默认为空;是否必传:否
80 | htmlwaterword: '',
81 | // 水印 RGBA(颜色和透明度),需要经过 URL 安全 的 Base64 编码,默认为:rgba(192,192,192,0.6);是否必传:否
82 | htmlfillstyle: '',
83 | // 水印文字样式,需要经过 URL 安全 的 Base64 编码,默认为:bold 20px Serif;是否必传:否
84 | htmlfront: '',
85 | // 水印文字旋转角度,0 - 360,默认315度;是否必传:否
86 | htmlrotate: '',
87 | // 水印文字水平间距,单位 px,默认为50;是否必传:否
88 | htmlhorizontal: '',
89 | // 水印文字垂直间距,单位 px,默认为100;是否必传:否
90 | htmlvertical: '',
91 | },
92 | },
93 | function (err, data) {
94 | if (err) {
95 | // 处理请求失败
96 | console.log(err);
97 | } else {
98 | // 处理请求成功
99 | console.log(data.Response);
100 | }
101 | }
102 | );
103 | }
104 |
105 | function getDocPreview() {
106 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
107 | const ObjectKey = 'test.docx';
108 | const key = `${ObjectKey}`; // ObjectKey:{ObjectKey};
109 | const host = `${config.Bucket}.cos.${config.Region}.myqcloud.com`;
110 | const url = `https://${host}/${key}`;
111 |
112 | cos.request(
113 | {
114 | Method: 'GET', // 固定值,必须
115 | Key: key, // 必须
116 | Url: url, // 请求的url,必须
117 | Query: {
118 | // 数据万象处理能力,文档预览固定为 doc-preview;是否必传:是
119 | 'ci-process': 'doc-preview',
120 | // 源数据的后缀类型,当前文档转换根据 COS 对象的后缀名来确定源数据类型。当 COS 对象没有后缀名时,可以设置该值;是否必传:否
121 | srcType: '',
122 | // 需转换的文档页码,默认从1开始计数;表格文件中 page 表示转换的第 X 个 sheet 的第 X 张图;是否必传:否
123 | page: 0,
124 | // 转换输出目标文件类型:png,转成 png 格式的图片文件jpg,转成 jpg 格式的图片文件pdf,转成 pdf 格式文件。 无法选择页码,page 参数不生效如果传入的格式未能识别,默认使用 jpg 格式;是否必传:否
125 | dstType: 'jpg',
126 | // Office 文档的打开密码,如果需要转换有密码的文档,请设置该字段;是否必传:否
127 | password: '',
128 | // 是否隐藏批注和应用修订,默认为00:隐藏批注,应用修订1:显示批注和修订;是否必传:否
129 | comment: 0,
130 | // 表格文件参数,转换第 X 个表,默认为1;是否必传:否
131 | sheet: 0,
132 | // 表格文件转换纸张方向,0代表垂直方向,非0代表水平方向,默认为0;是否必传:否
133 | excelPaperDirection: 0,
134 | // 设置纸张(画布)大小,对应信息为: 0 → A4 、 1 → A2 、 2 → A0 ,默认 A4 纸张 (需配合 excelRow 或 excelCol 一起使用);是否必传:否
135 | excelPaperSize: 0,
136 | // 转换后的图片处理参数,支持 基础图片处理 所有处理参数,多个处理参数可通过 管道操作符 分隔,从而实现在一次访问中按顺序对图片进行不同处理;是否必传:否
137 | ImageParams: '',
138 | // 生成预览图的图片质量,取值范围为 [1, 100],默认值100。 例如取值为100,代表生成图片质量为100%;是否必传:否
139 | quality: 0,
140 | // 预览图片的缩放参数,取值范围为 [10, 200], 默认值100。 例如取值为200,代表图片缩放比例为200% 即放大两倍;是否必传:否
141 | scale: 0,
142 | // 按指定 dpi 渲染图片,该参数与 scale 共同作用,取值范围 96-600 ,默认值为 96 。转码后的图片单边宽度需小于65500像素;是否必传:否
143 | imageDpi: 0,
144 | },
145 | },
146 | function (err, data) {
147 | if (err) {
148 | // 处理请求失败
149 | console.log(err);
150 | } else {
151 | // 处理请求成功
152 | console.log(data.Response);
153 | }
154 | }
155 | );
156 | }
157 |
158 | function createDocProcessJob() {
159 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
160 | const key = `doc_jobs`; //
161 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
162 | const url = `https://${host}/${key}`;
163 | const body = COS.util.json2xml({
164 | Request: {
165 | // 创建任务的 Tag,目前仅支持:DocProcess;是否必传:是
166 | Tag: 'DocProcess',
167 | // 待操作的文件对象;是否必传:是
168 | Input: {
169 | // 文件在 COS 上的文件路径,Bucket 由 Host 指定;是否必传:是
170 | Object: 'test.docx',
171 | },
172 | // 操作规则;是否必传:是
173 | Operation: {
174 | // 当 Tag 为 DocProcess 时有效,指定该任务的参数;是否必传:否
175 | DocProcess: {
176 | // 源数据的后缀类型,当前文档转换根据 cos 对象的后缀名来确定源数据类型,当 cos 对象没有后缀名时,可以设置该值;是否必传:否
177 | SrcType: '',
178 | // 转换输出目标文件类型:jpg,转成 jpg 格式的图片文件;如果传入的格式未能识别,默认使用 jpg 格式png,转成 png 格式的图片文件pdf,转成 pdf 格式文件(暂不支持指定页数);是否必传:否
179 | TgtType: '',
180 | // 从第 X 页开始转换;在表格文件中,一张表可能分割为多页转换,生成多张图片。StartPage 表示从指定 SheetId 的第 X 页开始转换。默认为1;是否必传:否
181 | StartPage: 1,
182 | // 转换至第 X 页;在表格文件中,一张表可能分割为多页转换,生成多张图片。EndPage 表示转换至指定 SheetId 的第 X 页。默认为-1,即转换全部页;是否必传:否
183 | EndPage: 2,
184 | // 表格文件参数,转换第 X 个表,默认为0;设置 SheetId 为0,即转换文档中全部表;是否必传:否
185 | SheetId: 0,
186 | // 表格文件转换纸张方向,0代表垂直方向,非0代表水平方向,默认为0;是否必传:否
187 | PaperDirection: 0,
188 | // 设置纸张(画布)大小,对应信息为: 0 → A4 、 1 → A2 、 2 → A0 ,默认 A4 纸张;是否必传:否
189 | PaperSize: 0,
190 | // 转换后的图片处理参数,支持 基础图片处理 所有处理参数,多个处理参数可通过 管道操作符 分隔,从而实现在一次访问中按顺序对图片进行不同处理;是否必传:否
191 | ImageParams: '',
192 | // 生成预览图的图片质量,取值范围 [1-100],默认值100。 例:值为100,代表生成图片质量为100%;是否必传:否
193 | Quality: 0,
194 | // 预览图片的缩放参数,取值范围[10-200], 默认值100。 例:值为200,代表图片缩放比例为200% 即放大两倍;是否必传:否
195 | Zoom: 100,
196 | // 按指定 dpi 渲染图片,该参数与 Zoom 共同作用,取值范围 96-600 ,默认值为 96 。转码后的图片单边宽度需小于65500像素;是否必传:否
197 | ImageDpi: 96,
198 | // 是否转换成单张长图,设置为 1 时,最多仅支持将 20 标准页面合成单张长图,超过可能会报错,分页范围可以通过 StartPage、EndPage 控制。默认值为 0 ,按页导出图片,TgtType="png"/"jpg" 时生效;是否必传:否
199 | PicPagination: 0,
200 | },
201 | // 结果输出地址;是否必传:是
202 | Output: {
203 | // 存储桶的地域;是否必传:是
204 | Region: config.Region,
205 | // 存储结果的存储桶;是否必传:是
206 | Bucket: config.Bucket,
207 | // 输出文件路径。非表格文件输出文件名需包含 ${Number} 或 ${Page} 参数。多个输出文件,${Number} 表示序号从1开始,${Page} 表示序号与预览页码一致。${Number} 表示多个输出文件,序号从1开始,例如输入 abc_${Number}.jpg,预览某文件5 - 6页,则输出文件名为 abc_1.jpg,abc_2.jpg${Page} 表示多个输出文件,序号与预览页码一致,例如输入 abc_${Page}.jpg,预览某文件5-6页,则输出文件名为 abc_5.jpg,abc_6.jpg表格文件输出路径需包含 ${SheetID} 占位符,输出文件名必须包含 ${Number} 参数。例如 /${SheetID}/abc_${Number}.jpg,先根据 excel 转换的表格数,生成对应数量的文件夹,再在对应的文件夹下,生成对应数量的图片文件;是否必传:是
208 | Object: '${Number}',
209 | },
210 | },
211 | // 任务所在的队列 ID,开通预览服务后自动生成,请使用 查询队列 获取或前往 万象控制台 在存储桶中查询 ;是否必传:否
212 | QueueId: '',
213 | },
214 | });
215 | cos.request(
216 | {
217 | Method: 'POST', // 固定值,必须
218 | Key: key, // 必须
219 | Url: url, // 请求的url,必须
220 | Body: body, // 请求体参数,必须
221 | ContentType: 'application/xml', // 固定值,必须
222 | },
223 | function (err, data) {
224 | if (err) {
225 | // 处理请求失败
226 | console.log(err);
227 | } else {
228 | // 处理请求成功
229 | console.log(data.Response);
230 | }
231 | }
232 | );
233 | }
234 |
235 | function describeDocProcessJob() {
236 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
237 | const jobId = 'xxx';
238 | const key = `doc_jobs/${jobId}`; // jobId:{jobId};
239 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
240 | const url = `https://${host}/${key}`;
241 |
242 | cos.request(
243 | {
244 | Method: 'GET', // 固定值,必须
245 | Key: key, // 必须
246 | Url: url, // 请求的url,必须
247 | },
248 | function (err, data) {
249 | if (err) {
250 | // 处理请求失败
251 | console.log(err);
252 | } else {
253 | // 处理请求成功
254 | console.log(data.Response);
255 | }
256 | }
257 | );
258 | }
259 |
260 | function describeDocProcessJobList() {
261 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
262 | const key = `doc_jobs`; //
263 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
264 | const url = `https://${host}/${key}`;
265 | cos.request(
266 | {
267 | Method: 'GET', // 固定值,必须
268 | Key: key, // 必须
269 | Url: url, // 请求的url,必须
270 | Query: {
271 | // 任务的 Tag:DocProcess;是否必传:是
272 | tag: 'DocProcess',
273 | // 拉取该队列 ID 下的任务,可在任务响应内容或控制台中获取;是否必传:否
274 | queueId: '',
275 | // Desc 或者 Asc。默认为 Desc;是否必传:否
276 | orderByTime: 'Desc',
277 | // 请求的上下文,用于翻页。上次返回的值;是否必传:否
278 | nextToken: '',
279 | // 拉取该状态的任务,以,分割,支持多状态:All、Submitted、Running、Success、Failed、Pause、Cancel。默认为 All;是否必传:否
280 | states: 'Success',
281 | // 拉取创建时间大于等于该时间的任务。格式为:%Y-%m-%dT%H:%m:%S%z;是否必传:否
282 | // startCreationTime: "",
283 | // 拉取创建时间小于等于该时间的任务。格式为:%Y-%m-%dT%H:%m:%S%z;是否必传:否
284 | // endCreationTime: "",
285 | },
286 | },
287 | function (err, data) {
288 | if (err) {
289 | // 处理请求失败
290 | console.log(err);
291 | } else {
292 | // 处理请求成功
293 | console.log(data.Response);
294 | }
295 | }
296 | );
297 | }
298 |
299 | function describeDocProcessQueue() {
300 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
301 | const key = `docqueue`; //
302 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
303 | const url = `https://${host}/${key}`;
304 | cos.request(
305 | {
306 | Method: 'GET', // 固定值,必须
307 | Key: key, // 必须
308 | Url: url, // 请求的url,必须
309 | Query: {
310 | // 队列 ID,以“,”符号分割字符串;是否必传:否
311 | queueIds: '',
312 | // 1. Active 表示队列内的作业会被文档预览服务调度执行2. Paused 表示队列暂停,作业不再会被文档预览服务调度执行,队列内的所有作业状态维持在暂停状态,已经处于执行中的任务将继续执行,不受影响;是否必传:否
313 | state: 'Active',
314 | // 第几页,默认第一页;是否必传:否
315 | pageNumber: '',
316 | // 每页个数,默认10个;是否必传:否
317 | pageSize: '',
318 | },
319 | },
320 | function (err, data) {
321 | if (err) {
322 | // 处理请求失败
323 | console.log(err);
324 | } else {
325 | // 处理请求成功
326 | console.log(data.Response);
327 | }
328 | }
329 | );
330 | }
331 |
332 | function updateProcessQueue() {
333 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
334 | const queueId = 'xxx';
335 | const key = `docqueue/${queueId}`;
336 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
337 | const url = `https://${host}/${key}`;
338 | const body = COS.util.json2xml({
339 | Request: {
340 | // 队列名称;是否必传:是
341 | Name: 'xxx',
342 | // 队列 ID;是否必传:是
343 | QueueID: queueId,
344 | // 队列状态;是否必传:是
345 | State: 'Active',
346 | // 通知渠道;是否必传:是
347 | NotifyConfig: {
348 | // 回调配置;是否必传:否
349 | Url: '',
350 | // 回调类型,普通回调:Url;是否必传:否
351 | Type: 'Url',
352 | // 回调事件,文档预览任务完成;是否必传:否
353 | Event: 'TaskFinish',
354 | // 回调开关,Off,On;是否必传:否
355 | State: 'Off',
356 | },
357 | },
358 | });
359 | cos.request(
360 | {
361 | Method: 'PUT', // 固定值,必须
362 | Key: key, // 必须
363 | Url: url, // 请求的url,必须
364 | Body: body, // 请求体参数,必须
365 | ContentType: 'application/xml', // 固定值,必须
366 | },
367 | function (err, data) {
368 | if (err) {
369 | // 处理请求失败
370 | console.log(err);
371 | } else {
372 | // 处理请求成功
373 | console.log(data.Response);
374 | }
375 | }
376 | );
377 | }
378 |
379 | module.exports = docPreviewDao;
380 |
--------------------------------------------------------------------------------
/demo/ciDemo/fileProcess.js:
--------------------------------------------------------------------------------
1 | const COS = require('../lib/cos-wx-sdk-v5');
2 | var wxfs = wx.getFileSystemManager();
3 | const config = require('../config');
4 | const { cos, requestCallback } = require('../tools');
5 |
6 | const fileProcessDao = {
7 | '开通文件处理服务 openFileProcessService': openFileProcessService,
8 | '查询文件处理服务 describeFileProcessService': describeFileProcessService,
9 | '关闭文件处理服务 closeFileProcessService': closeFileProcessService,
10 | '查询文件处理队列 describeFileProcessQueue': describeFileProcessQueue,
11 | '更新文件处理队列 updateFileProcessQueue': updateFileProcessQueue,
12 | '哈希值计算同步请求 fileHash': fileHash,
13 | '提交哈希值计算任务 createFileHashJob': createFileHashJob,
14 | '查询哈希值计算结果 describeFileHashJob': describeFileHashJob,
15 | '提交多文件打包压缩任务 createFileCompressJob': createFileCompressJob,
16 | '查询多文件打包压缩结果 describeFileCompressJob': describeFileCompressJob,
17 | '压缩包预览 zipPreview': zipPreview,
18 | '提交文件解压任务 createFileUnCompressJob': createFileUnCompressJob,
19 | '查询文件解压结果 describeFileUnCompressJob': describeFileUnCompressJob,
20 | };
21 |
22 | function openFileProcessService() {
23 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
24 | const key = `file_bucket`; //
25 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
26 | const url = `https://${host}/${key}`;
27 |
28 | cos.request(
29 | {
30 | Method: 'POST', // 固定值,必须
31 | Key: key, // 必须
32 | Url: url, // 请求的url,必须
33 | },
34 | function (err, data) {
35 | if (err) {
36 | // 处理请求失败
37 | console.log(err);
38 | } else {
39 | // 处理请求成功
40 | console.log(data.Response);
41 | }
42 | }
43 | );
44 | }
45 |
46 | function describeFileProcessService() {
47 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
48 | const key = `file_bucket`; //
49 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
50 | const url = `https://${host}/${key}`;
51 |
52 | cos.request(
53 | {
54 | Method: 'Get', // 固定值,必须
55 | Key: key, // 必须
56 | Url: url, // 请求的url,必须
57 | Query: {
58 | // regions: "", // 地域信息,例如 ap-shanghai、ap-beijing,若查询多个地域以“,”分隔字符串,非必须
59 | // bucketNames: "", // 存储桶名称,以“,”分隔,支持多个存储桶,精确搜索,非必须
60 | // bucketName: "", // 存储桶名称前缀,前缀搜索,非必须
61 | // pageNumber: "", // 第几页,非必须
62 | // pageSize: "", // 每页个数,大于0且小于等于100的整数,非必须
63 | },
64 | },
65 | function (err, data) {
66 | if (err) {
67 | // 处理请求失败
68 | console.log(err);
69 | } else {
70 | // 处理请求成功
71 | console.log(data.Response);
72 | }
73 | }
74 | );
75 | }
76 |
77 | function closeFileProcessService() {
78 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
79 | const key = `file_bucket`; //
80 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
81 | const url = `https://${host}/${key}`;
82 |
83 | cos.request(
84 | {
85 | Method: 'DELETE', // 固定值,必须
86 | Key: key, // 必须
87 | Url: url, // 请求的url,必须
88 | },
89 | function (err, data) {
90 | if (err) {
91 | // 处理请求失败
92 | console.log(err);
93 | } else {
94 | // 处理请求成功
95 | console.log(data.Response);
96 | }
97 | }
98 | );
99 | }
100 |
101 | function describeFileProcessQueue() {
102 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
103 | const key = `file_queue`; //
104 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
105 | const url = `https://${host}/${key}`;
106 |
107 | cos.request(
108 | {
109 | Method: 'GET', // 固定值,必须
110 | Key: key, // 必须
111 | Url: url, // 请求的url,必须
112 | Query: {
113 | // 队列 ID,以“,”符号分割字符串;是否必传:否
114 | queueIds: '',
115 | // Active 表示队列内的作业会被调度执行Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响;是否必传:否
116 | state: 'Active',
117 | // 第几页,默认值1;是否必传:否
118 | pageNumber: '',
119 | // 每页个数,默认值10;是否必传:否
120 | pageSize: '',
121 | },
122 | },
123 | function (err, data) {
124 | if (err) {
125 | // 处理请求失败
126 | console.log(err);
127 | } else {
128 | // 处理请求成功
129 | console.log(data.Response);
130 | }
131 | }
132 | );
133 | }
134 |
135 | function updateFileProcessQueue() {
136 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
137 | const queueId = 'xxx';
138 | const key = `file_queue/${queueId}`; // queueId:{queueId};
139 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
140 | const url = `https://${host}/${key}`;
141 | const body = COS.util.json2xml({
142 | Request: {
143 | // 队列名称,仅支持中文、英文、数字、_、-和*,长度不超过 128;是否必传:是
144 | Name: 'xxx',
145 | // Active 表示队列内的作业会被调度执行Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响;是否必传:是
146 | State: 'Active',
147 | // 回调配置;是否必传:是
148 | NotifyConfig: {
149 | // 回调开关OffOn;是否必传:否
150 | State: 'Off',
151 | // 回调事件TaskFinish:任务完成WorkflowFinish:工作流完成;是否必传:否
152 | Event: 'TaskFinish',
153 | // 回调格式XMLJSON;是否必传:否
154 | ResultFormat: '',
155 | // 回调类型UrlTDMQ;是否必传:否
156 | Type: 'Url',
157 | // 回调地址,不能为内网地址。;是否必传:否
158 | Url: '',
159 | // TDMQ 使用模式Topic:主题订阅Queue: 队列服务;是否必传:否
160 | MqMode: '',
161 | // TDMQ 所属园区,目前支持园区 sh(上海)、bj(北京)、gz(广州)、cd(成都)、hk(中国香港);是否必传:否
162 | MqRegion: '',
163 | // TDMQ 主题名称;是否必传:否
164 | MqName: '',
165 | },
166 | },
167 | });
168 | cos.request(
169 | {
170 | Method: 'PUT', // 固定值,必须
171 | Key: key, // 必须
172 | Url: url, // 请求的url,必须
173 | Body: body, // 请求体参数,必须
174 | ContentType: 'application/xml', // 固定值,必须
175 | },
176 | function (err, data) {
177 | if (err) {
178 | // 处理请求失败
179 | console.log(err);
180 | } else {
181 | // 处理请求成功
182 | console.log(data.Response);
183 | }
184 | }
185 | );
186 | }
187 |
188 | function fileHash() {
189 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
190 | const ObjectKey = 'test.docx';
191 | const key = `${ObjectKey}`; // ObjectKey:{ObjectKey};
192 | const host = `${config.Bucket}.cos.${config.Region}.myqcloud.com`;
193 | const url = `https://${host}/${key}`;
194 |
195 | cos.request(
196 | {
197 | Method: 'GET', // 固定值,必须
198 | Key: key, // 必须
199 | Url: url, // 请求的url,必须
200 | Query: {
201 | // 操作类型,哈希值计算固定为:filehash;是否必传:是
202 | 'ci-process': 'filehash',
203 | // 支持的哈希算法类型,有效值:md5、sha1、sha256;是否必传:是
204 | type: 'md5',
205 | // 是否将计算得到的哈希值,自动添加至文件的自定义header,格式为:x-cos-meta-md5/sha1/sha256;有效值: true、false,不填则默认为false;是否必传:否
206 | addtoheader: '',
207 | },
208 | },
209 | function (err, data) {
210 | if (err) {
211 | // 处理请求失败
212 | console.log(err);
213 | } else {
214 | // 处理请求成功
215 | console.log(data.Response);
216 | }
217 | }
218 | );
219 | }
220 |
221 | function createFileHashJob() {
222 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
223 | const key = `jobs`; //
224 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
225 | const url = `https://${host}/${key}`;
226 | const body = COS.util.json2xml({
227 | Request: {
228 | // 表示任务的类型,哈希值计算默认为:FileHashCode。;是否必传:是
229 | Tag: 'FileHashCode',
230 | // 包含待操作的文件信息。;是否必传:是
231 | Input: {
232 | // 文件名,取值为文件在当前存储桶中的完整名称。;是否必传:是
233 | Object: 'test.docx',
234 | },
235 | // 包含哈希值计算的处理规则。;是否必传:是
236 | Operation: {
237 | // 指定哈希值计算的处理规则。;是否必传:是
238 | FileHashCodeConfig: {
239 | // 哈希值的算法类型,支持:MD5、SHA1、SHA256;是否必传:是
240 | Type: 'MD5',
241 | // 是否将计算得到的哈希值添加至文件自定义header,有效值:true、false,默认值为 false。自定义header根据Type的值变化,例如Type值为MD5时,自定义header为 x-cos-meta-md5。;是否必传:否
242 | AddToHeader: '',
243 | },
244 | // 透传用户信息, 可打印的 ASCII 码,长度不超过1024。;是否必传:否
245 | UserData: '',
246 | },
247 | // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式。;是否必传:否
248 | CallBackFormat: '',
249 | // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型。;是否必传:否
250 | CallBackType: 'Url',
251 | // 任务回调的地址,优先级高于队列的回调地址。;是否必传:否
252 | CallBack: '',
253 | },
254 | });
255 | cos.request(
256 | {
257 | Method: 'POST', // 固定值,必须
258 | Key: key, // 必须
259 | Url: url, // 请求的url,必须
260 | Body: body, // 请求体参数,必须
261 | ContentType: 'application/xml', // 固定值,必须
262 | },
263 | function (err, data) {
264 | if (err) {
265 | // 处理请求失败
266 | console.log(err);
267 | } else {
268 | // 处理请求成功
269 | console.log(data.Response);
270 | }
271 | }
272 | );
273 | }
274 |
275 | function describeFileHashJob() {
276 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
277 | const jobId = 'xxx';
278 | const key = `file_jobs/${jobId}`; // jobId:{jobId};
279 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
280 | const url = `https://${host}/${key}`;
281 | cos.request(
282 | {
283 | Method: 'GET', // 固定值,必须
284 | Key: key, // 必须
285 | Url: url, // 请求的url,必须
286 | },
287 | function (err, data) {
288 | if (err) {
289 | // 处理请求失败
290 | console.log(err);
291 | } else {
292 | // 处理请求成功
293 | console.log(data.Response);
294 | }
295 | }
296 | );
297 | }
298 |
299 | function createFileCompressJob() {
300 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
301 | const key = `jobs`; //
302 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
303 | const url = `https://${host}/${key}`;
304 | const body = COS.util.json2xml({
305 | Request: {
306 | // 表示任务的类型,多文件打包压缩默认为:FileCompress。;是否必传:是
307 | Tag: 'FileCompress',
308 | // 包含文件打包压缩的处理规则。;是否必传:是
309 | Operation: {
310 | // 指定文件打包压缩的处理规则。;是否必传:是
311 | FileCompressConfig: {
312 | // 文件打包时,是否需要去除源文件已有的目录结构,有效值:0:不需要去除目录结构,打包后压缩包中的文件会保留原有的目录结构;1:需要,打包后压缩包内的文件会去除原有的目录结构,所有文件都在同一层级。例如:源文�� URL 为 https://domain/source/test.mp4,则源文件路径为 source/test.mp4,如果为 1,则 ZIP 包中该文件路径为 test.mp4;如果为0, ZIP 包中该文件路径为 source/test.mp4。;是否必传:是
313 | Flatten: '0',
314 | // 打包压缩的类型,有效值:zip、tar、tar.gz。;是否必传:是
315 | Format: 'zip',
316 | // 压缩类型,仅在Format为tar.gz或zip时有效。faster:压缩速度较快better:压缩质量较高,体积较小default:适中的压缩方式默认值为default;是否必传:否
317 | Type: '',
318 | // 压缩包密钥,传入时需先经过 base64 编码,编码后长度不能超过128。当 Format 为 zip 时生效。;是否必传:否
319 | CompressKey: '',
320 | // 支持将需要打包的文件整理成索引文件,后台将根据索引文件内提供的文件 url,打包为一个压缩包文件。索引文件需要保存在当前存储桶中,本字段需要提供索引文件的对象地址,例如:/test/index.csv。索引文件格式:仅支持 CSV 文件,一行一条 URL(仅支持本存储桶文件),如有多列字段,默认取第一列作为URL。最多不超过10000个文件, 总大小不超过50G,否则会导致任务失败。;是否必传:否
321 | UrlList: '',
322 | // 支持对存储桶中的某个前缀进行打包,如果需要对某个目录进行打包,需要加/,例如test目录打包,则值为:test/。最多不超过10000个文件,总大小不超过50G,否则会导致任务失败。;是否必传:否
323 | Prefix: 'example/',
324 | // 支持对存储桶中的多个文件进行打包,个数不能超过 1000,总大小不超过50G,否则会导致任务失败。;是否必传:否
325 | Key: '',
326 | },
327 | // 透传用户信息,可打印的 ASCII 码,长度不超过1024。;是否必传:否
328 | UserData: '',
329 | // 指定打包压缩后的文件保存的地址信息。;是否必传:是
330 | Output: {
331 | // 存储桶的地域。;是否必传:是
332 | Region: config.Region,
333 | // 保存压缩后文件的存储桶。;是否必传:是
334 | Bucket: config.Bucket,
335 | // 压缩后文件的文件名;是否必传:是
336 | Object: 'test.zip',
337 | },
338 | },
339 | // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式。;是否必传:否
340 | CallBackFormat: '',
341 | // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型。;是否必传:否
342 | CallBackType: 'Url',
343 | // 任务回调的地址,优先级高于队列的回调地址。;是否必传:否
344 | CallBack: '',
345 | },
346 | });
347 |
348 | cos.request(
349 | {
350 | Method: 'POST', // 固定值,必须
351 | Key: key, // 必须
352 | Url: url, // 请求的url,必须
353 | Body: body, // 请求体参数,必须
354 | ContentType: 'application/xml', // 固定值,必须
355 | },
356 | function (err, data) {
357 | if (err) {
358 | // 处理请求失败
359 | console.log(err);
360 | } else {
361 | // 处理请求成功
362 | console.log(data.Response);
363 | }
364 | }
365 | );
366 | }
367 |
368 | function describeFileCompressJob() {
369 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
370 | const jobId = 'xxx';
371 | const key = `file_jobs/${jobId}`; // jobId:{jobId};
372 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
373 | const url = `https://${host}/${key}`;
374 | cos.request(
375 | {
376 | Method: 'GET', // 固定值,必须
377 | Key: key, // 必须
378 | Url: url, // 请求的url,必须
379 | },
380 | function (err, data) {
381 | if (err) {
382 | // 处理请求失败
383 | console.log(err);
384 | } else {
385 | // 处理请求成功
386 | console.log(data.Response);
387 | }
388 | }
389 | );
390 | }
391 |
392 | function zipPreview() {
393 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
394 | const key = `test.zip`; //
395 | const host = `${config.Bucket}.cos.${config.Region}.myqcloud.com`;
396 | const url = `https://${host}/${key}`;
397 |
398 | cos.request(
399 | {
400 | Method: 'GET', // 固定值,必须
401 | Key: key, // 必须
402 | Url: url, // 请求的url,必须
403 | Query: {
404 | 'ci-process': 'zippreview', // 操作类型,压缩包预览计算固定为:zippreview,必须
405 | },
406 | },
407 | function (err, data) {
408 | if (err) {
409 | // 处理请求失败
410 | console.log(err);
411 | } else {
412 | // 处理请求成功
413 | console.log(data.Response);
414 | }
415 | }
416 | );
417 | }
418 |
419 | function createFileUnCompressJob() {
420 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
421 | const key = `jobs`; //
422 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
423 | const url = `https://${host}/${key}`;
424 | const body = COS.util.json2xml({
425 | Request: {
426 | // 表示任务的类型,文件解压默认为:FileUncompress。;是否必传:是
427 | Tag: 'FileUncompress',
428 | // 包含待操作的文件信息。;是否必传:是
429 | Input: {
430 | // 文件名,取值为文件在当前存储桶中的完整名称。;是否必传:是
431 | Object: 'test.zip',
432 | },
433 | // 包含文件解压的处理规则。;是否必传:是
434 | Operation: {
435 | // 指定文件解压的处理规则。;是否必传:是
436 | FileUncompressConfig: {
437 | // 指定解压后输出文件的前缀,不填则默认保存在存储桶根路径。;是否必传:否
438 | Prefix: 'output/',
439 | // 解压密钥,传入时需先经过 base64 编码。;是否必传:否
440 | UnCompressKey: '',
441 | // 指定解压后的文件路径是否需要替换前缀,有效值:0:不添加额外的前缀,解压缩将保存在Prefix指定的路径下(不会保留压缩包的名称,仅将压缩包内的文件保存至指定的路径)1:以压缩包本身的名称作为前缀,解压缩将保存在Prefix指定的路径下2:以压缩包完整路径作为前缀,此时如果不指定Prefix,就是解压到压缩包所在的当前路径(包含压缩包本身名称)默认值为0。;是否必传:否
442 | PrefixReplaced: '',
443 | },
444 | // 透传用户信息,可打印的 ASCII 码,长度不超过1024。;是否必传:否
445 | UserData: '',
446 | // 指定解压后的文件保存的存储桶信息。;是否必传:是
447 | Output: {
448 | // 存储桶的地域。;是否必传:是
449 | Region: config.Region,
450 | // 保存解压后文件的存储桶。;是否必传:是
451 | Bucket: config.Bucket,
452 | },
453 | },
454 | // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式。;是否必传:否
455 | CallBackFormat: '',
456 | // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型。;是否必传:否
457 | CallBackType: 'Url',
458 | // 任务回调的地址,优先级高于队列的回调地址。;是否必传:否
459 | CallBack: '',
460 | },
461 | });
462 | cos.request(
463 | {
464 | Method: 'POST', // 固定值,必须
465 | Key: key, // 必须
466 | Url: url, // 请求的url,必须
467 | Body: body, // 请求体参数,必须
468 | ContentType: 'application/xml', // 固定值,必须
469 | },
470 | function (err, data) {
471 | if (err) {
472 | // 处理请求失败
473 | console.log(err);
474 | } else {
475 | // 处理请求成功
476 | console.log(data.Response);
477 | }
478 | }
479 | );
480 | }
481 |
482 | function describeFileUnCompressJob() {
483 | // sdk引入以及初始化请参考:https://cloud.tencent.com/document/product/436/31953
484 | const jobId = 'xxx';
485 | const key = `file_jobs/${jobId}`; // jobId:{jobId};
486 | const host = `${config.Bucket}.ci.${config.Region}.myqcloud.com`;
487 | const url = `https://${host}/${key}`;
488 | cos.request(
489 | {
490 | Method: 'GET', // 固定值,必须
491 | Key: key, // 必须
492 | Url: url, // 请求的url,必须
493 | },
494 | function (err, data) {
495 | if (err) {
496 | // 处理请求失败
497 | console.log(err);
498 | } else {
499 | // 处理请求成功
500 | console.log(data.Response);
501 | }
502 | }
503 | );
504 | }
505 |
506 | module.exports = fileProcessDao;
507 |
--------------------------------------------------------------------------------
/demo/lib/beacon_mp.min.js:
--------------------------------------------------------------------------------
1 | /*! For license information please see beacon_mp.min.js.LICENSE.txt */
2 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.BeaconAction=e():t.BeaconAction=e()}(window,(function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=6)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BEACON_ATTA_REQUEST_URL=e.BEACON_ATTA_TOKEN=e.BEACON_ATTA_ID=e.BEACON_CONFIG_HTTPS_URL=e.BEACON_CONFIG_REQUEST_TIME=e.BEACON_CONFIG=e.BEACON_SENDING_IDS_KEY=e.BEACON_NORMAL_LOG_ID_KEY=e.BEACON_DRIECT_LOG_ID_KEY=e.BEACON_LASE_REPORT_TIME_KEY=e.BEACON_DEVICE_ID_KEY=e.BEACON_STORE_PREFIX=e.BEACON_LOG_ID_KEY=e.BEACON_IS_REALTIME_KEY=e.BEACON_DELAY_DEFAULT=e.BEACON_HTTPS_URL=e.BEACON_HTTP_URL=void 0,e.BEACON_HTTP_URL="http://oth.eve.mdt.qq.com:8080/analytics/v2_upload",e.BEACON_HTTPS_URL="https://otheve.beacon.qq.com/analytics/v2_upload",e.BEACON_DELAY_DEFAULT=3e3,e.BEACON_IS_REALTIME_KEY="A99",e.BEACON_LOG_ID_KEY="A100",e.BEACON_STORE_PREFIX="__BEACON_",e.BEACON_DEVICE_ID_KEY="__BEACON_deviceId",e.BEACON_LASE_REPORT_TIME_KEY="last_report_time",e.BEACON_DRIECT_LOG_ID_KEY="direct_log_id",e.BEACON_NORMAL_LOG_ID_KEY="normal_log_id",e.BEACON_SENDING_IDS_KEY="sending_event_ids",e.BEACON_CONFIG="beacon_config",e.BEACON_CONFIG_REQUEST_TIME="beacon_config_request_time",e.BEACON_CONFIG_HTTPS_URL="https://oth.str.beacon.qq.com/trpc.beacon.configserver.BeaconConfigService/QueryConfig",e.BEACON_ATTA_ID="00400014144",e.BEACON_ATTA_TOKEN="6478159937",e.BEACON_ATTA_REQUEST_URL="https://h.trace.qq.com/kv"},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.getEventId=e.replaceSymbol=e.replace=e.assert=void 0;var r=n(0),o=n(9);function i(t){if("string"!=typeof t)return t;try{return t.replace(new RegExp("\\|","g"),"%7C").replace(new RegExp("\\&","g"),"%26").replace(new RegExp("\\=","g"),"%3D").replace(new RegExp("\\+","g"),"%2B")}catch(t){return""}}Object.defineProperty(e,"EventEmiter",{enumerable:!0,get:function(){return o.EventEmiter}}),e.assert=function(t,e){if(!t)throw e instanceof Error?e:new Error(e)},e.replace=function(t,e){for(var n={},r=0,o=Object.keys(t);r60*this.strategy.requestInterval*1e3},t.prototype.getUploadUrl=function(){return this.strategy.httpsUploadUrl+"?appkey="+this.appkey},t.prototype.isBlackEvent=function(t){return-1!=this.strategy.blacklist.indexOf(t)},t.prototype.isEventUpOnOff=function(){return this.strategy.isEventUpOnOff},t.prototype.isSampleEvent=function(t){return!!Object.prototype.hasOwnProperty.call(this.realSample,t)&&this.realSample[t] {
32 | console.log(err || data);
33 | }
34 | );
35 | }
36 |
37 | function uploadFile() {
38 | var uploadFile = function (file) {
39 | cos.uploadFile(
40 | {
41 | Bucket: config.Bucket,
42 | Region: config.Region,
43 | Key: file.name,
44 | FilePath: file.path,
45 | FileSize: file.size,
46 | SliceSize: 1024 * 1024 * 5, // 文件大于5mb自动使用分块上传
47 | onTaskReady: function (taskId) {
48 | TaskId = taskId;
49 | },
50 | onProgress: function (info) {
51 | var percent = parseInt(info.percent * 10000) / 100;
52 | var speed = parseInt((info.speed / 1024 / 1024) * 100) / 100;
53 | console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
54 | },
55 | onFileFinish: function (err, data, options) {
56 | console.log(options.Key + '上传' + (err ? '失败' : '完成'));
57 | },
58 | },
59 | function (err, data) {
60 | console.log(err || data);
61 | }
62 | );
63 | };
64 | wx.chooseMedia({
65 | count: 1,
66 | mediaType: ['image', 'video'],
67 | sizeType: ['original'],
68 | sourceType: ['album', 'camera'],
69 | success: function (res) {
70 | const file = res.tempFiles[0];
71 | const filePath = file.tempFilePath;
72 | const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
73 | uploadFile({
74 | name: filename,
75 | path: filePath,
76 | size: file.size,
77 | });
78 | },
79 | });
80 | }
81 |
82 | function uploadFiles() {
83 | const uploadFiles = function (files) {
84 | const fileList = files.map(function (file) {
85 | const filePath = file.tempFilePath;
86 | const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
87 | return Object.assign({
88 | Bucket: config.Bucket,
89 | Region: config.Region,
90 | Key: filename,
91 | FilePath: filePath,
92 | });
93 | });
94 | cos.uploadFiles(
95 | {
96 | files: fileList,
97 | SliceSize: 1024 * 1024 * 5, // 文件大于5mb自动使用分块上传
98 | onProgress: function (info) {
99 | var percent = parseInt(info.percent * 10000) / 100;
100 | var speed = parseInt((info.speed / 1024 / 1024) * 100) / 100;
101 | console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
102 | },
103 | onFileFinish: function (err, data, options) {
104 | console.log(options.Key + '上传' + (err ? '失败' : '完成'));
105 | },
106 | },
107 | function (err, data) {
108 | console.log(err || data);
109 | }
110 | );
111 | };
112 | wx.chooseMedia({
113 | count: 9,
114 | mediaType: ['image', 'video'],
115 | sizeType: ['original'],
116 | sourceType: ['album', 'camera'],
117 | success: function (res) {
118 | uploadFiles(res.tempFiles);
119 | },
120 | });
121 | }
122 |
123 | function sliceUploadFile() {
124 | var sliceUploadFile = function (file) {
125 | const filePath = file.tempFilePath;
126 | const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
127 | var key = filename;
128 | cos.sliceUploadFile(
129 | {
130 | Bucket: config.Bucket,
131 | Region: config.Region,
132 | Key: key,
133 | FilePath: filePath,
134 | FileSize: file.size,
135 | CacheControl: 'max-age=7200',
136 | Headers: {
137 | aa: 123,
138 | },
139 | Query: {
140 | bb: 123,
141 | },
142 | onTaskReady: function (taskId) {
143 | TaskId = taskId;
144 | },
145 | onHashProgress: function (info) {
146 | console.log('check hash', JSON.stringify(info));
147 | },
148 | onProgress: function (info) {
149 | console.log(JSON.stringify(info));
150 | },
151 | },
152 | requestCallback
153 | );
154 | };
155 | wx.chooseMedia({
156 | count: 1,
157 | mediaType: ['image', 'video'],
158 | sizeType: ['original'],
159 | sourceType: ['album', 'camera'],
160 | success: function (res) {
161 | sliceUploadFile(res.tempFiles[0]);
162 | },
163 | });
164 | // wx.chooseVideo({
165 | // sourceType: ['album','camera'],
166 | // maxDuration: 60,
167 | // camera: 'back',
168 | // success(res) {
169 | // var name = res.tempFilePath.replace(/^.*?([^/]{32}\.\w+)$/, '$1');
170 | // sliceUploadFile({
171 | // name: name,
172 | // path: res.tempFilePath,
173 | // size: res.size,
174 | // });
175 | // },
176 | // fail(err) {
177 | // console.log(err);
178 | // }
179 | // })
180 | }
181 |
182 | function postObject() {
183 | wx.chooseMedia({
184 | count: 1, // 默认9
185 | mediaType: ['image', 'video'],
186 | sizeType: ['original'],
187 | sourceType: ['album', 'camera'],
188 | success: function (res) {
189 | var file = res.tempFiles[0];
190 | cos.postObject(
191 | {
192 | Bucket: config.Bucket,
193 | Region: config.Region,
194 | Key: '1.png',
195 | FilePath: file.tempFilePath,
196 | onTaskReady: function (taskId) {
197 | TaskId = taskId;
198 | },
199 | onProgress: function (info) {
200 | console.log(JSON.stringify(info));
201 | },
202 | },
203 | requestCallback
204 | );
205 | },
206 | });
207 | }
208 |
209 | function putObject() {
210 | wx.chooseMedia({
211 | count: 10,
212 | mediaType: ['image', 'video'],
213 | sizeType: ['original'],
214 | sourceType: ['album', 'camera'],
215 | success: function (res) {
216 | const file = res.tempFiles[0];
217 | const filePath = file.tempFilePath;
218 | const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
219 | wxfs.readFile({
220 | filePath: filePath,
221 | success: function (res) {
222 | cos.putObject(
223 | {
224 | Bucket: config.Bucket,
225 | Region: config.Region,
226 | Key: filename,
227 | Body: res.data, // 在小程序里,putObject 接口只允许传字符串的内容,不支持 TaskReady 和 onProgress,上传请使用 cos.postObject 接口
228 | Headers: {
229 | // 万象持久化接口,上传时持久化。例子:通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 200,宽度等比压缩
230 | // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "desample_photo.jpg", "rule": "imageMogr2/thumbnail/200x/"}]}'
231 | },
232 | },
233 | requestCallback
234 | );
235 | },
236 | fail: (err) => console.error(err),
237 | });
238 | },
239 | fail: (err) => console.error(err),
240 | });
241 | }
242 |
243 | function putObjectStr() {
244 | cos.putObject(
245 | {
246 | Bucket: config.Bucket,
247 | Region: config.Region,
248 | Key: '1.txt',
249 | Body: 'hello world', // 在小程序里,putObject 接口只允许传字符串的内容,不支持 TaskReady 和 onProgress,上传请使用 cos.postObject 接口
250 | Headers: {
251 | aa: 123,
252 | },
253 | Query: {
254 | bb: 123,
255 | },
256 | },
257 | requestCallback
258 | );
259 | }
260 |
261 | function putObjectBase64() {
262 | var base64Url =
263 | 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABRFBMVEUAAAAAo/8Ao/8Ao/8Ao/8ApP8Aov8Ao/8Abv8Abv8AyNwAyNwAo/8Ao/8Ao/8Abv8Ao/8AivgAo/8AyNwAbv8Abv8AydwApf8Abf8Ao/8AbP8Ao/8AyNwAydwAbv8AydwApP8Ao/8AyNwAo/8AyNwAydsAyNwAxd8Aov8AyNwAytsAo/8Abv8AyNwAbv8Av+MAo/8AytsAo/8Abv8AyNwAo/8Abv8AqfkAbv8Aov8Abv8AyNwAov8Abv8Ao/8Abv8Ao/8AydwAo/8Ao/8Ate8Ay9oAvOcAof8AveAAyNwAyNwAo/8AyNwAy9kAo/8AyNwAyNwAo/8AqP8Aaf8AyNwAbv0Abv8Abv8AaP8Ao/8Ao/8Ao/8Ao/8Abv8AyNwAgvcAaP8A0dkAo/8AyNwAav8Abv8Ao/8Abv8AyNwAy9sAvOUAtePdkYxjAAAAZnRSTlMAw/co8uAuJAn8+/Tt29R8DAX77+nZz87Jv6CTh3lxTklAPjouJRsL5tjAuLiyr62roaCakYp0XVtOQTMyLiohICAcGRP49vTv5+PJurawq6mnnJuYl4+OiIB7eXVvX15QSDgqHxNcw3l6AAABe0lEQVQ4y82P11oCQQxGIy5FUJpKk6aAhV6k92LvvXedDfj+92ZkYQHxnnMxu3/OfJMEJo6y++baXf5XVw22GVGcsRmq431mQZRYyIzRGgdXi+HwIv86NDBKisrRAtU1hSj9pkZ9jpo/9YKbRsmNNKCHDXI00BxfMMirKNpMcjQ5Lm4/YZArUXyBYUwg40nsdr5jb3LBe25VWpNeKa1GENsEnq52C80z1uW48estiKjb19G54QdCrScnKAU69U3KJ4jzrsBawDWPuOcBqMyRvlcb1Y+zjMUBVsivAKe4gXgEKiVjSh9wlunGMmwiOqFL3RI0cj+nkgp3jC1BELVFkGiZSuvkp3tZZWZ2sKCuDj185PXqfmwI7AAOUctHkJoOeXg3sxA4ES+l7CVvrYHMEmNp8GtR+wycPG0+1RrwWQUzl4CvgQmPP5Ddofl8tWkJVT7J+BIAaxEktrYZoRAUfXgOGYHfcOqw3WF/EdLccz5cMfvUCPb4QwUmhB8+v12HZPCkbgAAAABJRU5ErkJggg==';
264 | var m = /data:image\/(\w+);base64,(.*)/.exec(base64Url) || [];
265 | var format = m[1];
266 | var bodyData = m[2];
267 | var fileBuf = wx.base64ToArrayBuffer(bodyData);
268 | cos.putObject(
269 | {
270 | Bucket: config.Bucket,
271 | Region: config.Region,
272 | Key: '1.' + format,
273 | Body: fileBuf,
274 | },
275 | requestCallback
276 | );
277 | }
278 |
279 | function getObjectUrl() {
280 | var url = cos.getObjectUrl(
281 | {
282 | Bucket: config.Bucket, // Bucket 格式:test-1250000000
283 | Region: config.Region,
284 | Key: '1mb.zip',
285 | Expires: 60,
286 | Sign: true,
287 | },
288 | function (err, data) {
289 | console.log(err || data);
290 | }
291 | );
292 | console.log(url);
293 | }
294 |
295 | var toolsDao = {
296 | request: request,
297 | 'uploadFile 高级上传': uploadFile,
298 | 'uploadFiles 批量上传': uploadFiles,
299 | 'sliceUploadFile 分片上传': sliceUploadFile,
300 | // 上传文件适用于单请求上传大文件
301 | 'postObject 简单上传': postObject,
302 | 'putObject 简单上传文件': putObject,
303 | 'putObject 上传字符串': putObjectStr,
304 | // 上传文件
305 | 'putObject base64 转 ArrayBuffer 上传': putObjectBase64,
306 | 'getObjectUrl 获取对象访问url': getObjectUrl,
307 | };
308 |
309 | var bucketDao = {
310 | // Service
311 | 'getService 获取存储桶列表': function () {
312 | cos.getService(requestCallback);
313 | },
314 | // 简单 Bucket 操作
315 | 'putBucket 创建存储桶': function () {
316 | cos.putBucket(
317 | {
318 | Bucket: config.Bucket,
319 | Region: config.Region,
320 | },
321 | requestCallback
322 | );
323 | },
324 | 'headBucket 检索存储桶及其权限': function () {
325 | cos.headBucket(
326 | {
327 | Bucket: config.Bucket,
328 | Region: config.Region,
329 | },
330 | requestCallback
331 | );
332 | },
333 | 'deleteBucket 删除存储桶': function () {
334 | cos.deleteBucket(
335 | {
336 | Bucket: config.Bucket,
337 | Region: config.Region,
338 | },
339 | requestCallback
340 | );
341 | },
342 | 'getBucketACL 查询存储桶 ACL': function () {
343 | cos.getBucketAcl(
344 | {
345 | Bucket: config.Bucket,
346 | Region: config.Region,
347 | },
348 | requestCallback
349 | );
350 | },
351 | 'putBucketACL 设置存储桶 ACL': function () {
352 | cos.putBucketAcl(
353 | {
354 | Bucket: config.Bucket,
355 | Region: config.Region,
356 | ACL: 'public-read',
357 | },
358 | requestCallback
359 | );
360 | },
361 | 'getBucketCors 查询跨域配置': function () {
362 | cos.getBucketCors(
363 | {
364 | Bucket: config.Bucket,
365 | Region: config.Region,
366 | },
367 | requestCallback
368 | );
369 | },
370 | 'putBucketCors 设置跨域配置': function () {
371 | cos.putBucketCors(
372 | {
373 | Bucket: config.Bucket,
374 | Region: config.Region,
375 | ResponseVary: 'true',
376 | CORSRules: [
377 | {
378 | AllowedOrigin: ['*'],
379 | AllowedMethod: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'],
380 | AllowedHeader: ['*'],
381 | ExposeHeader: ['ETag', 'Content-Length'],
382 | MaxAgeSeconds: '5',
383 | },
384 | ],
385 | },
386 | requestCallback
387 | );
388 | },
389 | 'deleteBucketCors 删除跨域配置': function () {
390 | cos.deleteBucketCors(
391 | {
392 | Bucket: config.Bucket,
393 | Region: config.Region,
394 | },
395 | requestCallback
396 | );
397 | },
398 | 'putBucketPolicy 设置存储桶策略': function () {
399 | var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1);
400 | cos.putBucketPolicy(
401 | {
402 | Bucket: config.Bucket,
403 | Region: config.Region,
404 | Policy: {
405 | version: '2.0',
406 | principal: {
407 | qcs: ['qcs::cam::uin/10001:uin/10001'],
408 | }, // 这里的 10001 是 QQ 号
409 | statement: [
410 | {
411 | effect: 'allow',
412 | action: [
413 | 'name/cos:GetBucket',
414 | 'name/cos:PutObject',
415 | 'name/cos:PostObject',
416 | 'name/cos:PutObjectCopy',
417 | 'name/cos:InitiateMultipartUpload',
418 | 'name/cos:UploadPart',
419 | 'name/cos:UploadPartCopy',
420 | 'name/cos:CompleteMultipartUpload',
421 | 'name/cos:AbortMultipartUpload',
422 | 'name/cos:AppendObject',
423 | ],
424 | // "resource": ["qcs::cos:ap-guangzhou:uid/1250000000:test-1250000000/*"] // 1250000000 是 appid
425 | resource: ['qcs::cos:' + config.Region + ':uid/' + AppId + ':' + config.Bucket + '/*'], // 1250000000 是 appid
426 | },
427 | ],
428 | },
429 | },
430 | requestCallback
431 | );
432 | },
433 | 'getBucketPolicy 查询存储桶策略': function () {
434 | cos.getBucketPolicy(
435 | {
436 | Bucket: config.Bucket,
437 | Region: config.Region,
438 | },
439 | requestCallback
440 | );
441 | },
442 | 'deleteBucketPolicy 删除存储桶策略': function () {
443 | cos.deleteBucketPolicy(
444 | {
445 | Bucket: config.Bucket,
446 | Region: config.Region,
447 | },
448 | requestCallback
449 | );
450 | },
451 | 'getBucketLocation 获取Bucket的地域信息': function () {
452 | cos.getBucketLocation(
453 | {
454 | Bucket: config.Bucket,
455 | Region: config.Region,
456 | },
457 | requestCallback
458 | );
459 | },
460 | 'getBucketTagging 获取Bucket标签': function () {
461 | cos.getBucketTagging(
462 | {
463 | Bucket: config.Bucket,
464 | Region: config.Region,
465 | },
466 | requestCallback
467 | );
468 | },
469 | 'putBucketTagging 设置Bucket标签': function () {
470 | cos.putBucketTagging(
471 | {
472 | Bucket: config.Bucket,
473 | Region: config.Region,
474 | Tagging: {
475 | Tags: [
476 | {
477 | Key: 'k1',
478 | Value: 'v1',
479 | },
480 | {
481 | Key: 'k2',
482 | Value: 'v2',
483 | },
484 | ],
485 | },
486 | },
487 | requestCallback
488 | );
489 | },
490 | 'deleteBucketTagging 删除存储桶标签': function () {
491 | cos.deleteBucketTagging(
492 | {
493 | Bucket: config.Bucket,
494 | Region: config.Region,
495 | },
496 | requestCallback
497 | );
498 | },
499 | };
500 |
501 | var objectDao = {
502 | 'getBucket 获取对象列表': function () {
503 | cos.getBucket(
504 | {
505 | Bucket: config.Bucket,
506 | Region: config.Region,
507 | },
508 | requestCallback
509 | );
510 | },
511 | // 上传文件适用于单请求上传大文件
512 | 'postObject 表单上传对象': postObject,
513 | 'putObject 简单上传文件': putObject,
514 | 'putObject 上传字符串': putObjectStr,
515 | // 上传文件
516 | 'putObject base64 转 ArrayBuffer 上传': putObjectBase64,
517 | 'getObject 下载对象': function () {
518 | cos.getObject(
519 | {
520 | Bucket: config.Bucket,
521 | Region: config.Region,
522 | Key: '1.png',
523 | },
524 | function (err, data) {
525 | console.log('getObject:', err || data);
526 | }
527 | );
528 | },
529 | 'abortUploadTask 抛弃分块上传任务': function () {
530 | cos.abortUploadTask(
531 | {
532 | Bucket: config.Bucket,
533 | /* 必须 */ // Bucket 格式:test-1250000000
534 | Region: config.Region,
535 | /* 必须 */
536 | // 格式1,删除单个上传任务
537 | // Level: 'task',
538 | // Key: '10mb.zip',
539 | // UploadId: '14985543913e4e2642e31db217b9a1a3d9b3cd6cf62abfda23372c8d36ffa38585492681e3',
540 | // 格式2,删除单个文件所有未完成上传任务
541 | Level: 'file',
542 | Key: '10mb.zip',
543 | // 格式3,删除 Bucket 下所有未完成上传任务
544 | // Level: 'bucket',
545 | },
546 | requestCallback
547 | );
548 | },
549 | 'deleteObject 删除文件': function () {
550 | cos.deleteObject(
551 | {
552 | Bucket: config.Bucket,
553 | Region: config.Region,
554 | Key: '1.zip',
555 | },
556 | requestCallback
557 | );
558 | },
559 | };
560 |
561 | var advanceObjectDao = {
562 | 'sliceUploadFile 分块上传': function () {
563 | var sliceUploadFile = function (file) {
564 | const filePath = file.tempFilePath;
565 | const filename = filePath.substr(filePath.lastIndexOf('/') + 1);
566 | var key = filename;
567 | cos.sliceUploadFile(
568 | {
569 | Bucket: config.Bucket,
570 | Region: config.Region,
571 | Key: key,
572 | FilePath: filePath,
573 | FileSize: file.size,
574 | CacheControl: 'max-age=7200',
575 | Headers: {
576 | aa: 123,
577 | },
578 | Query: {
579 | bb: 123,
580 | },
581 | onTaskReady: function (taskId) {
582 | TaskId = taskId;
583 | },
584 | onHashProgress: function (info) {
585 | console.log('check hash', JSON.stringify(info));
586 | },
587 | onProgress: function (info) {
588 | console.log(JSON.stringify(info));
589 | },
590 | },
591 | requestCallback
592 | );
593 | };
594 | wx.chooseMedia({
595 | count: 1,
596 | mediaType: ['image', 'video'],
597 | sizeType: ['original'],
598 | sourceType: ['album', 'camera'],
599 | success: function (res) {
600 | sliceUploadFile(res.tempFiles[0]);
601 | },
602 | });
603 | // wx.chooseVideo({
604 | // sourceType: ['album','camera'],
605 | // maxDuration: 60,
606 | // camera: 'back',
607 | // success(res) {
608 | // var name = res.tempFilePath.replace(/^.*?([^/]{32}\.\w+)$/, '$1');
609 | // sliceUploadFile({
610 | // name: name,
611 | // path: res.tempFilePath,
612 | // size: res.size,
613 | // });
614 | // },
615 | // fail(err) {
616 | // console.log(err);
617 | // }
618 | // })
619 | },
620 | 'sliceCopyFile 分块复制对象': function () {
621 | // 创建测试文件
622 | var sourceName = '1.txt';
623 | var Key = '1.slicecopy.exe';
624 |
625 | var sourcePath = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + sourceName;
626 |
627 | cos.sliceCopyFile(
628 | {
629 | Bucket: config.Bucket, // Bucket 格式:test-1250000000
630 | Region: config.Region,
631 | Key: Key,
632 | CopySource: sourcePath,
633 | SliceSize: 20 * 1024 * 1024, // 大于20M的文件用分片复制,小于则用单片复制
634 | onProgress: function (info) {
635 | var percent = parseInt(info.percent * 10000) / 100;
636 | var speed = parseInt((info.speed / 1024 / 1024) * 100) / 100;
637 | console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
638 | },
639 | },
640 | requestCallback
641 | );
642 | },
643 | cancelTask: function () {
644 | cos.cancelTask(TaskId);
645 | console.log('canceled');
646 | },
647 | pauseTask: function () {
648 | cos.pauseTask(TaskId);
649 | console.log('paused');
650 | },
651 | restartTask: function () {
652 | cos.restartTask(TaskId);
653 | console.log('restart');
654 | },
655 | };
656 |
657 | // require('./test');
658 |
659 | module.exports = {
660 | toolsDao: toolsDao,
661 | bucketDao: bucketDao,
662 | objectDao: objectDao,
663 | advanceObjectDao: advanceObjectDao,
664 | };
665 |
--------------------------------------------------------------------------------