完成常用方法
parent
1ddf3df083
commit
6f9c0b0f4a
174
src/index.js
174
src/index.js
|
@ -0,0 +1,174 @@
|
||||||
|
/**
|
||||||
|
* 阿里云oss, 自签名
|
||||||
|
* @author yutent<yutent@doui.cc>
|
||||||
|
* @date 2020/01/18 14:28:47
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { hmac, base64encode } from 'crypto'
|
||||||
|
import xml2js from './lib/xml2js.js'
|
||||||
|
import {
|
||||||
|
APP_ID,
|
||||||
|
APP_KEY,
|
||||||
|
MIME_TYPES,
|
||||||
|
DEFAULT_MIME_TYPE
|
||||||
|
} from './lib/constants.js'
|
||||||
|
import { getMimeType, fixFile, str2sign } from './lib/helper.js'
|
||||||
|
|
||||||
|
export default class Alioss {
|
||||||
|
#bucket = ''
|
||||||
|
#domain = ''
|
||||||
|
#api = ''
|
||||||
|
|
||||||
|
constructor(bucket, domain, region) {
|
||||||
|
this.#bucket = bucket
|
||||||
|
this.#domain = domain
|
||||||
|
this.#api = `https://${bucket}.${region}.aliyuncs.com`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 授权签名, 用于临时下载私有bucket的文件
|
||||||
|
auth(key) {
|
||||||
|
var time = Math.floor(Date.now() / 1000) + 1800 // 半小时内
|
||||||
|
|
||||||
|
return hmac(
|
||||||
|
'SHA-1',
|
||||||
|
`GET\n\n\n${time}\n/${this.#bucket}/${key}`,
|
||||||
|
APP_KEY,
|
||||||
|
'base64'
|
||||||
|
).then(signature => {
|
||||||
|
return `?OSSAccessKeyId=${APP_ID}&Expires=${time}&Signature=${encodeURIComponent(
|
||||||
|
signature
|
||||||
|
)}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {生成签名, 需传入 , 大小限制}
|
||||||
|
* dir: 上传目录名
|
||||||
|
* size: 大小限制, 单位 MB 默认10MB
|
||||||
|
*/
|
||||||
|
sign(dir = '', size = 10) {
|
||||||
|
var time = new Date()
|
||||||
|
var params = {
|
||||||
|
conditions: [
|
||||||
|
['content-length-range', 0, Math.floor(1024 * 1024 * size)],
|
||||||
|
['starts-with', '$key', dir ? dir.replace(/\/+$/, '') + '/' : '']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
var policy = ''
|
||||||
|
|
||||||
|
time.setTime(time.getTime() + 60 * 60 * 1000) // 60分钟内有效
|
||||||
|
params.expiration = time.toISOString()
|
||||||
|
|
||||||
|
policy = JSON.stringify(params)
|
||||||
|
policy = btoa(policy)
|
||||||
|
return hmac('SHA-1', policy, APP_KEY, 'base64').then(signature => {
|
||||||
|
return { policy, signature, id: APP_ID }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
list({ prefix = '', delimiter = '/', max = 1000, token } = {}) {
|
||||||
|
var time = new Date().toGMTString()
|
||||||
|
var query = {
|
||||||
|
'list-type': 2,
|
||||||
|
prefix,
|
||||||
|
delimiter,
|
||||||
|
'max-keys': max,
|
||||||
|
'continuation-token': token
|
||||||
|
}
|
||||||
|
return hmac(
|
||||||
|
'SHA-1',
|
||||||
|
`GET\n\n\n${time}\nx-oss-date:${time}\n/${this.#bucket}/${
|
||||||
|
token ? '?continuation-token=' + token : ''
|
||||||
|
}`,
|
||||||
|
APP_KEY,
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
.then(signature =>
|
||||||
|
fetch(this.#api + '?' + query.toParams(), {
|
||||||
|
headers: {
|
||||||
|
'content-type': void 0,
|
||||||
|
authorization: `OSS ${APP_ID}:${signature}`,
|
||||||
|
'x-oss-date': time
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(r => xml2js(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {上传文件}
|
||||||
|
* auth: 上面的sign签名结果
|
||||||
|
* file: 要上传的文件 <Blob> | <File>
|
||||||
|
* key: 要保存的文件名, 带完整路径
|
||||||
|
*/
|
||||||
|
upload(auth, file, key) {
|
||||||
|
var body = new FormData()
|
||||||
|
|
||||||
|
if (!file.type) {
|
||||||
|
let ext = file.name.split('.').pop()
|
||||||
|
if (ext && MIME_TYPES[ext]) {
|
||||||
|
file = fixFile(ext, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.append('key', key) //
|
||||||
|
body.append('policy', auth.policy)
|
||||||
|
body.append('OSSAccessKeyId', auth.id)
|
||||||
|
body.append('Signature', auth.signature)
|
||||||
|
body.append('file', file)
|
||||||
|
|
||||||
|
return fetch(this.#api, { method: 'POST', body }).then(
|
||||||
|
r => this.#domain + key
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(origin, target) {
|
||||||
|
var time = new Date().toGMTString()
|
||||||
|
var headers = {
|
||||||
|
'x-oss-date': time,
|
||||||
|
'x-oss-copy-source': `/${this.#bucket}/${encodeURIComponent(origin)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return hmac(
|
||||||
|
'SHA-1',
|
||||||
|
str2sign('PUT', this.#bucket, {
|
||||||
|
time,
|
||||||
|
headers,
|
||||||
|
key: target
|
||||||
|
}),
|
||||||
|
APP_KEY,
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
.then(signature =>
|
||||||
|
fetch(`${this.#api}/${target}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
authorization: `OSS ${APP_ID}:${signature}`,
|
||||||
|
...headers
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(e => console.log(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(key) {
|
||||||
|
var time = new Date().toGMTString()
|
||||||
|
|
||||||
|
return hmac(
|
||||||
|
'SHA-1',
|
||||||
|
`DELETE\n\n\n${time}\nx-oss-date:${time}\n/${this.#bucket}/${key}`,
|
||||||
|
APP_KEY,
|
||||||
|
'base64'
|
||||||
|
).then(signature =>
|
||||||
|
fetch(`${this.#api}/${key}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'content-type': void 0,
|
||||||
|
authorization: `OSS ${APP_ID}:${signature}`,
|
||||||
|
'x-oss-date': time
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* {}
|
||||||
|
* @author yutent<yutent.io@gmail.com>
|
||||||
|
* @date 2023/02/17 16:00:06
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const DEFAULT_MIME_TYPE = 'application/octet-stream'
|
||||||
|
|
||||||
|
export const MIME_TYPES = {
|
||||||
|
html: 'text/html',
|
||||||
|
json: 'application/json',
|
||||||
|
js: 'application/javascript',
|
||||||
|
htm: 'text/html',
|
||||||
|
txt: 'text/plain',
|
||||||
|
css: 'text/css',
|
||||||
|
webp: 'image/webp',
|
||||||
|
jpg: 'image/jpg',
|
||||||
|
jpeg: 'image/jpeg',
|
||||||
|
png: 'image/png',
|
||||||
|
gif: 'image/gif',
|
||||||
|
svg: 'image/svg+xml',
|
||||||
|
ico: 'image/ico',
|
||||||
|
mp3: 'audio/mpeg',
|
||||||
|
ogg: 'audio/ogg',
|
||||||
|
m4a: 'audio/m4a',
|
||||||
|
amr: 'audio/amr',
|
||||||
|
mp4: 'video/mp4',
|
||||||
|
webm: 'video/webm',
|
||||||
|
wasm: 'application/wasm',
|
||||||
|
zip: 'application/zip',
|
||||||
|
'7z': 'application/x-7z-compressed',
|
||||||
|
eot: 'application/vnd.ms-fontobject',
|
||||||
|
ttf: 'font/ttf',
|
||||||
|
otf: 'font/otf',
|
||||||
|
woff: 'font/woff',
|
||||||
|
woff2: 'font/woff2',
|
||||||
|
xls: 'application/vnd.ms-excel',
|
||||||
|
doc: 'application/msword',
|
||||||
|
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* {}
|
||||||
|
* @author yutent<yutent.io@gmail.com>
|
||||||
|
* @date 2023/02/17 19:14:08
|
||||||
|
*/
|
||||||
|
import { MIME_TYPES, DEFAULT_MIME_TYPE } from './constants.js'
|
||||||
|
|
||||||
|
// 把文件大小, 转为友好的格式
|
||||||
|
export function parseSize(num) {
|
||||||
|
if (num < 1024) {
|
||||||
|
return `${num} B`
|
||||||
|
} else {
|
||||||
|
num = (num / 1024).toFixed(2) - 0
|
||||||
|
|
||||||
|
if (num < 1024) {
|
||||||
|
return `${num} KB`
|
||||||
|
} else {
|
||||||
|
num = (num / 1024).toFixed(2) - 0
|
||||||
|
return `${num} MB`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件的拓展名
|
||||||
|
export function getExt(str = '') {
|
||||||
|
let tmp = str.split('.')
|
||||||
|
let ext
|
||||||
|
|
||||||
|
if (tmp.length > 1) {
|
||||||
|
ext = tmp.pop()
|
||||||
|
if (ext === 'xz' || ext === 'gz') {
|
||||||
|
ext = tmp.pop() + ext
|
||||||
|
}
|
||||||
|
return ext
|
||||||
|
}
|
||||||
|
return 'unknow'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMimeType(name) {
|
||||||
|
var ext = getExt(name)
|
||||||
|
return MIME_TYPES[ext] || DEFAULT_MIME_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fixFile(name, data) {
|
||||||
|
return new File([data], name, { type: getMimeType(name) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成要签名的字符串
|
||||||
|
export function str2sign(
|
||||||
|
method = 'GET',
|
||||||
|
bucket,
|
||||||
|
{ time, headers = {}, key, query } = {}
|
||||||
|
) {
|
||||||
|
let arr = [
|
||||||
|
method,
|
||||||
|
'', // 请求内容的md5值, 用于服务端校验文件是否完整. 可以为空
|
||||||
|
'', // 请求文件的content-type类型, 可以为空
|
||||||
|
time,
|
||||||
|
Object.keys(headers)
|
||||||
|
.sort()
|
||||||
|
.map(k => `${k}:${headers[k]}`)
|
||||||
|
.join('\n'),
|
||||||
|
`/${bucket}/${key + (query || '')}`
|
||||||
|
]
|
||||||
|
return arr.join('\n')
|
||||||
|
}
|
Loading…
Reference in New Issue