上傳時計算文件hash 這樣可以減少成本
之前的邏輯是前端將文件上傳到業(yè)務服務器思灰,業(yè)務服務器計算hash康愤,已上傳的話直接返回hash對應的文件名稱儡循,沒有再上傳然后保存文件名稱于hash,這樣缺點就是服務器往阿里云還要傳一次征冷,比較費時
直傳的話計算出hash择膝,然后md5 再直接上傳覆蓋
export interface BaseResponse<T = undefined> {
status: number
data: T
msg: string
}
// oss配置
export interface OssConfig {
accessid: string
host: string
expire: number
signature: string
policy: string
dir: string
}
/**
* 從服務端獲取OSS配置
* @returns {Promise<AxiosResponse<BaseResponse<OssConfig>>>>}
*/
export function ossConfig() {
return axios.get('/oss/config');
}
/**
* 初始化Oss配置
* @returns {Promise<OssConfig>}
*/
export function initOssConfig() {
return new Promise((resolve, reject) => {
// 從本地localstore從獲取配置
const conf = store.get('ossConfig')
if (conf) {
// 配置存在并且距離過期時間還大于3秒則返回此配置
const now = new Date().getTime() / 1000
if (conf.expire - 3 > now) {
resolve(conf)
return
}
}
ElLoading.service({text: "獲取上傳配置"})
// 請求接口返回配置數(shù)據(jù)
ossConfig()
.then((resp) => {
if (resp.status === 0) {
resolve(resp.data);
// 配置數(shù)據(jù)寫入本地store
store.set('ossConfig', resp.data)
} else {
reject(resp)
ElMessage.error("獲取上傳配置失敗")
}
})
.catch((err) => {
console.log(err);
ElMessage.error("獲取上傳配置失敗")
reject(err)
})
})
}
/**
* 往Oss上傳文件
* @param file File對象
* @returns {Promise<{name:string,host:string}>}
*/
export function ossUpload(file) {
return new Promise((resolve, reject) => {
initOssConfig()
.then(async (ossConf) => {
const config = {
timeout: 1000 * 60 * 10,
headers: {'Content-Type': 'multipart/form-data'}
}
// 計算文件Hash 避免多余的文件上傳,這樣做的目的是盡量少占用OSS的空間
const name = await fileHash(file) + fileSuffix(file.name)
const formData = new FormData()
const key = `${ossConf.dir}${name}`
formData.append('name', name)
formData.append('key', key)
formData.append('policy', ossConf?.policy)
formData.append('OSSAccessKeyId', ossConf?.accessid)
formData.append('success_action_status', '200')
formData.append('signature', ossConf.signature)
formData.append('file', file)
axios
.post(ossConf.host, formData, config)
.then((resp) => {
resolve({name: key, host: ossConf.host})
})
.catch((err) => reject(err))
})
.catch((err)=>{
console.log(err);
reject({msg: '上傳失敗'})
})
})
}
yarn add crypto-js
yarn add file-to-array-buffer
import { lib, SHA256 } from 'crypto-js'
import fileToArrayBuffer from 'file-to-array-buffer'
// 獲取文件后綴
export function fileSuffix(filename) {
const pos = filename.lastIndexOf('.')
let suffix = ''
if (pos !== -1) {
suffix = filename.substring(pos)
}
return suffix;
}
export function arrayBufferToWordArray(ab) {
const i8a = new Uint8Array(ab)
const a = []
for (let i = 0; i < i8a.length; i += 4) {
a.push((i8a[i] << 24) | (i8a[i + 1] << 16) | (i8a[i + 2] << 8) | i8a[i + 3])
}
return lib.WordArray.create(a, i8a.length)
}
// 獲取文件Hash
export async function fileHash(file) {
const buffer = await fileToArrayBuffer(file)
return SHA256(arrayBufferToWordArray(buffer)).toString()
}
使用示例
element plus
用vant基本差不多
const handleBeforeUpload = (file) => {
const loading = ElLoading.service({
lock: true,
text: '請稍后',
background: 'rgba(0, 0, 0, 0.4)',
})
ossUpload(file)
.then(({host,name}) => {
loading.close();
console.log(host + name)
})
.catch((err) => {
console.log(err);
loading.close();
ElMessage.error("上傳文件失敗")
})
return false;
}