背景:一方面,部分系统对文件的私密性和安全性要求较高,文件通过互联网传输,若加密密码保存在服务端,依旧存在一定风险,故项目内实现前端打包加密,由上传者输入密钥,在前端完成加密打包,用户保存文件密钥,下载时手动输入密钥并解压文件。另一方面,传输压缩包到客户端,节约了带宽,节约了传输时间。
使用的库: zip.js 以下为vue的实现方案:
- 加密上传文件
import * as zip from '@zip.js/zip.js'
...
...
methods: {
async handleZipFile () {
const controller = new AbortController()
const signal = controller.signal
var zipWriter = new zip.ZipWriter(new zip.BlobWriter('application/zip'))
await Promise.all(_.map(this.files, async (file) => {
await zipWriter.add(file.name, new zip.BlobReader(file.raw), {
bufferedWrite: true,
password: this.password,
signal,
zipCrypto: true,
onprogress: (index, max) => {
const percent = parseInt(index / max * 100 || 0)
this.loadingText = `正在打包文件${file.name},进度为${percent}%`
}
})
}))
let [err, data] = await callAsync(zipWriter.close())
if (data) {
await this.uploadFile(new File([data], this.name + '.zip'))
}
},
async uploadFile (file) {
let formdata = new FormData()
formdata.append('file', file)
formdata.append('type', this.type) // 其他字段
let [err, res] = await callAsync(axios({
url: `/api/upload`,
method: 'post',
data: formdata,
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 0,
onUploadProgress: progressEvent => {
let percent = (progressEvent.loaded / progressEvent.total * 100 | 0)
this.loadingText = `正在上传文件${file.name},进度为${percent}%`
}
}))
if (err) {
if (axios.isCancel(err)) {
this.$message.success('已取消上传')
} else {
this.$message.error('文件上传失败' + err)
}
} else {
this.loadingText = ''
}
}
}
- 解密解压文件
methods: {
async getZipFiles (password, fileUrl, projectId) {
try {
const reader = new zip.ZipReader(new zip.HttpReader(fileUrl, {}), {
password: password
})
const entries: any = await reader.getEntries()
await reader.close()
return [null, { password: password, files: entries }]
} catch (err) {
return [{ msg: err.toString() }, null]
}
}
}