当前位置: 首页 > 工具软件 > Zip.js > 使用案例 >

前端zip.js实现加密打包上传文件

凌炜
2023-12-01

背景:一方面,部分系统对文件的私密性和安全性要求较高,实现前端加密打包,服务端不存储密码 ,下载时手动输入密钥并解压文件。另一方面,传输压缩包到客户端,节约了带宽,节约了传输时间。

使用的库: zip.js

  • Support of the Zip64 format
  • Support of WinZIP AES and PKWare ZipCrypto encryption
  • Support of simultaneous reads and writes to one or more zip files
  • Integrated worker pool manager
  • No dependencies

安装

 npm install @zip.js/zip.js 

引用

import * as zip from "@zip.js/zip.js";      //ES6 module
const zip = require("@zip.js/zip.js");     // or CommonJS module

实现

以下为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]
    }
  }
}

下载压缩文件中的指定文件


methods: {
    async downloadUnZipFile (file) {
      const getURL = async (entry, options) => {
        return URL.createObjectURL(await entry.getData(new zip.BlobWriter(), options))
      }
      const controller = new AbortController()
      const signal = controller.signal
      await getURL(file, {
        password: this.password,
        onprogress: (index, max) => {
          console.log(index, max)
        },
        onerror: (err) => {
          this.$message.error(err.toString())
        },
        signal
      }).then((blobURL) => {
        // 下载文件
        const a = document.createElement('a')
	    a.href = blobURL
	    a.download = file.filename
	    a.target = '_blank'
	    const clickEvent = new MouseEvent('click')
	    a.dispatchEvent(clickEvent)
      }).catch((err) => {
        this.$message.error(err.toString())
      })
    }
}

实际使用中,如果压缩文件很大,如上G的文件,可能会出现错误。

 类似资料: