nestjs后端生成cos临时密钥
import { Controller, Get } from '@nestjs/common';
import { getCredential } from 'qcloud-cos-sts';
import { AuthService } from './auth.service';
const policy = function () {
const LongBucketName = 'video-1309614912';
const Region = 'ap-guangzhou';
const ShortBucketName = LongBucketName.substr(0, LongBucketName.indexOf('-'));
const AppId = LongBucketName.substr(LongBucketName.indexOf('-') + 1);
return {
version: '2.0' ,
statement: [
{
action: [
'name/cos:PutObject',
'name/cos:PostObject',
'name/cos:InitiateMultipartUpload',
'name/cos:ListMultipartUploads',
'name/cos:ListParts',
'name/cos:UploadPart',
'name/cos:CompleteMultipartUpload',
'name/cos:uploadFiles',
] ,
effect: 'allow' ,
principal: { qcs: ['*'] } ,
resource: [
'qcs::cos:' +
Region +
':uid/' +
AppId +
':prefix//' +
AppId +
'/' +
ShortBucketName +
'/*',
] ,
},
],
};
};
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Get('key')
async getCosKey() {
const res = await this.getKey();
console.log(
'🚀 ~ file: auth.controller.ts:74 ~ AuthController ~ getCosKey ~ res:',
res,
);
return res;
}
getKey() {
return new Promise((resolve, reject) => {
getCredential(
{
secretId: 'cos的secretId',
secretKey: 'cos的secretKey',
policy: policy(),
durationSeconds: 7200,
},
(err, credential) => {
return resolve(credential);
},
);
});
}
}
前端获取临时cos上传视频
- 封装上传工具方法
import COS from 'cos-js-sdk-v5'
import { uploadImageApi } from '@/services/modules/common/upload'
import { getCosKey } from '@/services'
function dataURLtoFile(dataurl, filename, type) {
const arr = dataurl.split(',')
const bstr = window.atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, {
type: type
})
}
export function uploadImg(file, insertFn) {
const readObj = new FileReader()
readObj.onload = async () => {
let canvas = document.createElement('canvas')
let img = document.createElement('img')
img.src = readObj.result
img.onload = async () => {
canvas.width = 300
canvas.height = 300 * (img.height / img.width)
let ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, 300, 300 * (img.height / img.width))
let newImgBase64 = canvas.toDataURL(file.type, 10 / 100)
const newFile = dataURLtoFile(
newImgBase64,
file.name,
file.type
)
console.log(newFile, 'newFile')
const form = new FormData()
form.append('file', newFile, newFile.name)
const res = await uploadImageApi(form)
insertFn(res.data.url, '', '')
}
}
readObj.readAsDataURL(file)
}
export function uploadVideo(editor, file, insertFn) {
var cos = new COS({
getAuthorization: function (options, callback) {
var url = 'http://localhost:3000/auth/key';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
try {
var data = JSON.parse(e.target.responseText);
var credentials = data.credentials;
} catch (e) {
}
if (!data || !credentials) {
return console.error('credentials invalid:\n' + JSON.stringify(data, null, 2))
};
callback({
TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
SecurityToken: credentials.sessionToken,
StartTime: data.startTime,
ExpiredTime: data.expiredTime,
});
};
xhr.send();
}
});
cos.uploadFile(
{
Bucket: 'video-1309614912',
Region: 'ap-guangzhou' ,
Key: file.name,
Body: file,
SliceSize: 1024 * 1024 * 5,
onProgress: function (progressData) {
console.log(JSON.stringify(progressData))
editor.showProgressBar(progressData.percent * 100)
},
onFileFinish: function (err, data, options) {
console.log(options.Key + '上传' + (err ? '失败' : '完成'))
if (!err) {
}
}
},
(err, data) => { }
)
const videoURL = getFileURL(cos, file)
insertFn(videoURL)
}
function getFileURL(cos, file, Bucket = 'video-1309614912', Region = 'ap-guangzhou') {
const url = cos.getObjectUrl(
{
Bucket: Bucket,
Region: Region,
Key: file.name,
Sign: true
},
function (err, data) {
if (err) return console.log(err)
var url = data.Url
var downloadUrl =
url +
(url.indexOf('?') > -1 ? '&' : '?') +
'response-content-disposition=attachment'
}
)
return url
}
function FileExist(cos, file, Bucket = 'video-1309614912', Region = 'ap-guangzhou') {
cos.headObject({
Bucket: Bucket,
Region: Region,
Key: file.name,
}, function (err, data) {
if (data) {
console.log('对象存在');
return true
} else if (err.statusCode == 404) {
console.log('对象不存在');
return false
} else if (err.statusCode == 403) {
console.log('没有该对象读权限');
}
});
}
- 使用
wangEditor 上传
<template>
<div
class="pt-editor"
style="border: 1px solid #ccc; border-radius: 5px; overflow: auto"
>
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editor"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
class=""
:style="`height: ${height}px; overflow-y: hidden`"
v-bind:value="editorValue"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="onCreated"
@onChange="onChange"
/>
</div>
</template>
<script>
import Vue from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { uploadImg, uploadVideo } from '@/utils/uploadTools'
export default Vue.extend({
components: { Editor, Toolbar },
model: {
prop: 'editorValue',
event: 'change'
},
props: {
height: {
type: Number,
default: 500
},
editorValue: {
type: String,
default: ''
},
mode: {
type: String,
default: 'default'
}
},
data() {
let self = this
return {
editor: null,
html: this.editorValue.startsWith('<p>')
? this.editorValue
: `<p>${this.editorValue}</p>`,
toolbarConfig: {
excludeKeys: [
'blockquote',
'bgColor',
'todo',
'emotion',
'fullScreen',
'insertTable'
]
},
editorConfig: { placeholder: '请输入内容...' },
showContent: '',
editorConfig: {
MENU_CONF: {
uploadImage: {
fieldName: 'file',
async customUpload(file, insertFn) {
uploadImg(file, insertFn)
}
},
uploadVideo: {
async customUpload(file, insertFn) {
uploadVideo(self.editor, file, insertFn)
}
}
}
}
}
},
methods: {
onCreated(editor) {
this.editor = Object.seal(editor)
},
onChange(editor) {
this.$emit('change', this.editor.getHtml())
}
},
mounted() {},
beforeDestroy() {
const editor = this.editor
if (editor == null) return
editor.destroy()
}
})
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style>
/**
.w-e-progress-bar {
position: relative;
z-index: 99;
height: 5px;
background-color: rgb(10, 251, 10);
}
</style>