腾讯云对象存储COS的使用教程,node获取签名,js上传 您所在的位置:网站首页 腾讯云cos使用签名失败 腾讯云对象存储COS的使用教程,node获取签名,js上传

腾讯云对象存储COS的使用教程,node获取签名,js上传

#腾讯云对象存储COS的使用教程,node获取签名,js上传| 来源: 网络整理| 查看: 265

腾讯云对象存储的使用

这里忽略创建存储桶之类的操作。 说明:本示例使用nuxt服务端渲染 + koa框架

万事第一步:npm install ~~~ npm i qcloud-cos-sts --save

node sdk

注意:qcloud-cos-sts 只能在服务端中使用。 第二步:设置授权策略

// 示例 创建一个oss文件夹在controllers下面,项目结构自行更改。 // ../controllers/oss/index.js let STS = require('qcloud-cos-sts'); import jwt from '../../../jwt.js'; // 封装的jwt方法 import { response as R } from '../../controllers/unifyResponse'; // 这里对数据封装了统一返回格式,后面会附上封装源码。 // ······ /** * 授权策略 * @param {String} LongBucketName 桶名 * @param {String} Region 桶区域 */ let policy = function(LongBucketName, Region) { // let LongBucketName = 'public-***********'; // let Region = 'ap-beijing'; let ShortBucketName = LongBucketName.substr(0, LongBucketName.indexOf('-')); let AppId = LongBucketName.substr(LongBucketName.indexOf('-') + 1); return { version: '2.0' /* 策略语法版本,默认为2.0 */, statement: [ { action: [ // '*' // 所有 action 请看文档 https://cloud.tencent.com/document/product/436/31923 // 简单上传 'name/cos:PutObject', 'name/cos:PostObject', // 分片上传 'name/cos:InitiateMultipartUpload', 'name/cos:ListMultipartUploads', 'name/cos:ListParts', 'name/cos:UploadPart', 'name/cos:CompleteMultipartUpload', 'name/cos:uploadFiles' ] /* 此处是指 COS API,根据需求指定一个或者一序列操作的组合或所有操作(*) */, effect: 'allow' /* 有 allow (允许)和 deny (显式拒绝)两种情况 */, principal: { qcs: ['*'] } /* 委托人 授权子账户权限 */, resource: ['qcs::cos:' + Region + ':uid/' + AppId + ':prefix//' + AppId + '/' + ShortBucketName + '/*'] /* 授权操作的具体数据,可以是任意资源、指定路径前缀的资源、指定绝对路径的资源或它们的组合 */ } ] }; };

第三步:接下来获取临时签名

/** * 鉴权获取oss临时密钥接口 * @param {*} ctx nuxt上下文对象 * @param {*} next 执行下一步 * @returns 返回临时密钥 */ let getOssKey = (ctx, next) => { return new Promise(async (resolve, reject) => { try { // await jwt.verifyToken(ctx, next); /* 这里是对于用户访问进行鉴权,可以根据实际项目需求修改。 */ STS.getCredential( { secretId: 'AKID3zjGZgCxCOQCk8IBxWwAC0ZigU4tpzBQ', secretKey: '2rRmsxlSxDGZdWSGtJrBqGYeaNxiSUIr', policy: policy(ctx.request.body.Bucket, ctx.request.body.Region), durationSeconds: 7200 }, async (err, credential) => { console.log(err || credential) // 这里拿到错误或者临时签名信息。 /* R.send()为封装的统一返回方法,请自行删减。 */ return resolve((ctx.body = await R.send(200, err || credential))); } ); } catch (error) { // console.log('getOssKey:', error); return resolve((ctx.body = error)); } }); }; export default { getOssKey /* 获取临时密钥 */ };

我这是暴露了一个接口供前端调用

// 多余说明: const Router = require('koa-router'); const router = new Router({ prefix: '/koaApi/manage' }); // prefix 为router前缀,根据具体需求增删改~。 import oss from "../controllers/oss/index"; router.post('/getOssKey', oss.getOssKey);

ok 服务端这时候拿到临时COS的签名,下面则是客户端的骚操作了。

前端请求格式多余赘述:

axios API 封装格式。( 后面附上 server+client 统一axios请求拦截器 ) export const getOssKey = async params => { return await global.axios.$post(`/manage/getOssKey`, params); }; // 调用api使用 getOssKey({ Bucket: 'public-********', Region: 'ap-beijing' }) 直接使用 axios 请求 axios.$post(`/manage/getOssKey`, { Bucket: 'public-********', Region: 'ap-beijing' }); 客户端COS上传

第一步:下载cos-js-sdk-v5,很抱歉万年不变的定律npm install在这里行不通,使用 npm包下载的sdk运行貌似有问题,各种报错。( 或者你们可以尝试一下 😊) 我们通过gayhub下载~ 点击进入查看源码 👉cos-js-sdk-v5,将源码复制下载放在static或者plugins文件夹即可。

第二步:引入 plugins 从nuxt.config.js中配置plugins 注意:cos-js-sdk-v5 只能在客户端中使用。

// nuxt.config.js plugins:[{ src: '~/static/cos-js-sdk.js', mode: 'client' }]

第三步:客户端COS上传jssdk模块封装

import { getOssKey } from '../../assets/utils/api.js'; // 封装的api接口 import { Toast } from 'vant'; // 这里使用了vant的loading,可自行增删。 import meth from './meth.js'; // 封装的公用methods模块,下面附上meth模块中使用到的方法。如果只需要测试上传demo 那么只需要拿取其中的random_string+randomSign方法即可。 // ... // 进入正题 export default new (class { constructor() {} _cos(obj = { Bucket: 'public-********', Region: 'ap-beijing' }) { return new COS({ getAuthorization: function(options, callback) { getOssKey({ Bucket: obj.Bucket, Region: obj.Region }).then(config => { callback({ TmpSecretId: config.data.credentials.tmpSecretId, TmpSecretKey: config.data.credentials.tmpSecretKey, XCosSecurityToken: config.data.credentials.sessionToken, ExpiredTime: config.data.expiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization // ScopeLimit: true, // 细粒度控制权限设为 true,会限制密钥只在相同请求时重复使用 FileParallelLimit: 3, // 控制文件上传并发数 ChunkParallelLimit: 8 // 控制单个文件下分片上传并发数,在同园区上传可以设置较大的并发数 // ChunkSize: 1024 * 1024 * 8, // 控制分片大小,单位 B,在同园区上传可以设置较大的分片大小 }); }); } }); } /** * 文件直传 * @param {Object} obj Bucket、Region、Body 详情查看cos文档 * @returns err || data */ putObject(obj) { return new Promise((resolve, reject) => { this._cos(obj).putObject( { Bucket: obj.Bucket, Region: obj.Region, Key: `${meth.randomSign(3)}.${obj.Body[0].name.split('.')[1]}`, Body: obj.Body[0], onTaskReady: function(taskId) { /* 执行队列taskId */ console.log('taskId:', taskId); }, onProgress: info => { var percent = parseInt(info.percent * 10000) / 100; var speed = parseInt((info.speed / 1024 / 1024) * 100) / 100; console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); this.loading('进度:' + percent + '%'); } }, (err, data) => { Toast.clear(); return err ? Toast.fail('上传失败') && reject(err) : Toast.success('上传成功') && resolve(data); } ); }); } /** * 文件分块上传 * @param {Object} obj Bucket、Region、Body 详情查看cos文档 * @returns err || data */ sliceUploadFile(obj) { return new Promise((resolve, reject) => { this._cos(obj).sliceUploadFile( { Bucket: obj.Bucket, Region: obj.Region, Key: `${meth.randomSign(3)}.${obj.Body[0].name.split('.')[1]}`, Body: obj.Body[0], onTaskReady: function(taskId) { /* 执行队列taskId */ console.log('taskId:', taskId); }, onProgress: progressData => { /* 非必须 */ var percent = parseInt(progressData.percent * 10000) / 100; var speed = parseInt((progressData.speed / 1024 / 1024) * 100) / 100; console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); this.loading('进度:' + parseInt(percent) + '%'); } }, (err, data) => { Toast.clear(); return err ? Toast.fail('上传失败') && reject(err) : Toast.success('上传成功') && resolve(data); } ); }); } /** * 批量上传 * @param {Object} obj Bucket、Region、Body 详情查看cos文档 * @returns err || 批量上传filesData */ MultiFiles(obj) { return new Promise(async (resolve, reject) => { let files = await [...obj.Body].map(file => ({ Bucket: obj.Bucket, Region: obj.Region, Key: `${meth.randomSign(3)}.${file.name.split('.')[1]}`, Body: file })); await this._cos({ Bucket: obj.Bucket, Region: obj.Region }).uploadFiles( { files: files, SliceSize: 1024 * 1024, onTaskReady: function(taskId) { /* 执行队列taskId */ // console.log("taskId:",taskId); }, onProgress: info => { var percent = parseInt(info.percent * 10000) / 100; var speed = parseInt((info.speed / 1024 / 1024) * 100) / 100; console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); this.loading('进度:' + percent + '%'); }, onFileFinish: (err, data, options) => { console.log(options.Key + '上传' + (err ? '失败' : '完成')); } }, (err, data) => { Toast.clear(); return err ? Toast.fail('上传失败') && reject(err) : Toast.success('上传成功') && resolve(data); } ); }); } loading(text) { try { Toast.loading({ duration: 0, // 持续展示 toast forbidClick: true, message: text }); } catch (error) { console.log(error); } } })(); client 客户端COS API调用

putObject 文件直传

await tools.putObject({ Bucket: 'public-********', /* 必须 */ Region: 'ap-beijing', /* 必须 */ Body: e.target.files })

sliceUploadFile 分块上传

await tools.sliceUploadFile({ Bucket: 'public-********', /* 必须 */ Region: 'ap-beijing', /* 必须 */ Body: e.target.files })

MultiFiles 批量上传 需要设置 input 为 multiple

await tools.MultiFiles({ Bucket: 'public-********', /* 必须 */ Region: 'ap-beijing', /* 必须 */ Body: e.target.files })

这里便可以实现客户端使用cos-js-sdk进行上传文件了 示例图: 在这里插入图片描述 在这里插入图片描述

下面附上公用方法

meth.js 说明:上传的Key使用了meth中的随机字符串方法randomSign

export default new (class { constructor() {} /** * 设置cookie * @param {String} name cookie的名称 * @param {String} value cookie的值 * @param {Number} expiredays cookie的过期时间 */ setCookie(name, value, expiredays) { var exdate = new Date(); exdate.setDate(exdate.getDate() + expiredays); document.cookie = name + '=' + encodeURI(value) + (expiredays == null ? '' : ';expires=' + exdate.toGMTString()); } /** * 获取cookie * @param {String} name cookie的名称 */ getCookie(name) { var arr, reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); if ((arr = document.cookie.match(reg))) { return arr[2]; } else { return null; } } /** * 删除cookie * @param {String} name cookie的名称 */ delCookie(name) { var exp = new Date(); exp.setTime(exp.getTime() - 1); var cval = this.getCookie(name); if (cval != null) { document.cookie = name + '=' + cval + ';expires=' + exp.toGMTString(); } } /** * 表单上传转formdata编码 * @param {Object} data * @returns formdata */ fromData(data) { if (process.client) { let formData = new FormData(); Object.entries(data).map(([k, v]) => { formData.append(k, v); }); return formData; } } /** * 生成随机数 * @param {Num} len 需要生成的随机数长度 */ random_string(len) { //获取随机名 len = len || 32; let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; let maxPos = chars.length; let pwd = ''; for (let i = 0; i return `${this.random_string(len)}-${parseInt(Math.floor(Math.random() * Date.now()) / 1000)}`; } //建立一个可存取到该file的url getObjectURL(file) { var url = null; if (window.createObjectURL != undefined) { // basic url = window.createObjectURL(file); } else if (window.URL != undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file); } else if (window.webkitURL != undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file); } return url; } })(); jwt封装方法

jwt.js

/* * @Author: yaodongyi * @Date: 2019-09-29 16:01:09 * @Description:jsonwebtoken */ // jwt生成token const jwt = require('jsonwebtoken'); import { response as R } from './db/controllers/unifyResponse'; // 封装的统一响应状态结果 const serect = 'serect'; /** * 生成token * @param {Object} userinfo 用户信息 * @returns token */ let addToken = async userinfo => { //创建token并导出 const token = jwt.sign( { name: userinfo.name, id: userinfo.id }, serect, { expiresIn: '7d' } ); return token; }; /** * 验证token是否过期 * @param {String} tokens * @returns false未过期,true过期 */ let verifyToken = (ctx, next) => { return new Promise((resolve, rejects) => { let token = ctx.request.header.token || ctx.request.header.cookie; if (!token) { return rejects(R.send(0, {}, '暂未登录,请先进行登录')); } try { resolve(Object.assign(200, jwt.verify(token, serect))); } catch (err) { return rejects(R.send(0, err, '登录失效,请重新登录')); } }); }; /** * 解密token * @param {Object} tokens * @returns 解密后信息 */ let decodeToken = tokens => { if (tokens) { let decoded = jwt.decode(tokens, serect); return decoded; } }; /** * @description demo * @example * try { * console.log(jwt.verifyToken(jwt.addToken({ name: 'ydy', id: 1 }))); * } catch (error) { * console.log(error); * } */ module.exports = { addToken: addToken, decodeToken: decodeToken, verifyToken: verifyToken }; 统一返回数据格式封装

unifyResponse.js

/* * @Author: yaodongyi * @Date: 2019-09-30 14:46:07 * @Description: */ export const response = new (class { constructor() { /** * 返回结构体 */ this.response = { result: { code: new Number(), // 200:success, 0:error, default 0:Invalid msg: new String() // description }, data: new Object() // 响应body体 }; } /** * 设置统一返回结构 * @param {*} code 返回状态码 * @param {*} data 返回的数据源 * @param {*} description 返回的msg * @returns {Object} { result: { code: Number, msg: String }, data: Object } */ send(code, data, description) { switch (code) { case 200: return Object.assign({}, this.response, { data: data, result: { code: 200, msg: description || 'Success' } }); case 0: return Object.assign({}, this.response, { result: { code: 0, msg: description || 'Error' } }); default: return Object.assign({}, this.response, { result: { code: 0, msg: description || 'Invalid' } }); } } })(); 封装统一axios请求拦截器

plugins/http.js

/* * @Author: yaodongyi * @Date: 2019-07-26 16:12:05 * @Description:axios请求相应拦截器 */ // import qs from 'qs'; // import { Notification } from 'element-ui'; // import { res_decode } from '../assets/utils/encode'; // import meth from '../assets/utils/meth'; // 如果后端服务器地址和前端服务器域名不同 or 生产环境/开发环境 域名不同,则对应设置域名。 // const baseURL = process.env.NODE_ENV === 'development' ? '/koaApi' : 'http://www.baidu.com'; let getCookie = (cookie = '', name) => (cookie.match(new RegExp('(^| )' + name + '=([^;]*)(;|$)')) ? cookie.match(new RegExp('(^| )' + name + '=([^;]*)(;|$)'))[2] : null); export default function(ctx, inject) { // ctx.$axios.defaults.timeout = 6000; ctx.$axios.interceptors.request.use(request => { // console.log(request.headers.common); request.headers = Object.assign( { // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Content-Type': request.headers.ContentType ? request.headers.ContentType : 'application/json; charset=UTF-8', //json Accept: 'application/json' }, { ...(process.server && { Authorization: getCookie(request.headers.common.cookie, 'token') || '' }), ...(process.client && { token: sessionStorage.getItem('token') || '' }) } ); if (process.client) { request.baseURL = '/koaApi'; console.log(`%c 发送 ${request.baseURL}${request.url} `, 'background:#00CC6E;color:#ffffff', request); } return request; }); ctx.$axios.onRequestError(config => { console.error('请求错误' + config); }); ctx.$axios.interceptors.response.use( response => { // console.log(process.server, 'response.data', response); // response.data.data.encodeType && res_decode(response); // 这里是rsa解密,根据具体需求进行增删。 if (process.server) return Promise.resolve(response); if (response.status === 200) { if (response.data.result.code === 200) { console.log(`%c 接收 ${response.config.url} `, 'background:#1E1E1E;color:#bada55', response); } else { // Notification({ // message: response.data.result.msg, // type: 'warning' // }); console.error(`接收 ${response.config.url} `, response); } } else { console.error(`接收 ${response.config.url} `, response); } return Promise.resolve(response); }, error => { return Promise.reject(error); } ); ctx.$axios.onError(config => { console.error('错误' + config); }); /* 坑点,注入全局做法。 */ global = Object.assign(global, { axios: ctx.$axios }); }

nuxt.config.js中引入plugins

plugins:['~/plugins/http']

封装统一管理 API 接口

export const getOssKey = async params => { return await global.axios.$post(`/manage/getOssKey`, params); };

使用:

getOssKey({ Bucket: obj.Bucket, Region: obj.Region }).then(res=>{ // ... }).catch(err=>{ // ... }) // or async func(){ await getOssKey({ Bucket: obj.Bucket, Region: obj.Region }) }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有