完成常用方法
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