需求场景: 前端拿到下载文件的url,请求并将文件进行分类压缩生成压缩包导出
前端导出文件的优点:
-
减轻服务器负担: 后端生成压缩文件可能会占用服务器资源和时间。如果压缩的内容很大,可能会导致服务器压力增加,影响其他用户的访问速度。将这些任务转移到前端可以减轻服务器负担,提高整体系统的性能和稳定性。
-
用户体验: 前端实现可以提供更即时的用户反馈,用户可以立即看到下载进度和结果。此外,用户不需要等待服务器响应,可以立即开始下载,提高了用户体验。
-
灵活性和可控性: 前端可以更灵活地控制下载和压缩过程,根据用户的操作或需求进行相应的处理。例如,可以根据用户的选择动态生成压缩文件,或者根据用户的操作实时更新下载进度。
-
客户端资源利用: 前端实现可以充分利用客户端的计算资源,如浏览器的性能和内存,更高效地处理文件下载和压缩。
尽管在某些情况下,后端生成压缩文件可能更合适,特别是当需要处理大量或敏感数据时,为了确保安全性和数据完整性,可以在服务器端完成文件处理。但总体来说,在大多数情况下,将文件下载和压缩任务放在前端实现更为合适。
解决方案
使用jszip和file-saver插件
JSZip
和 FileSaver
是 JavaScript 库,它们分别用于处理压缩文件和文件保存的操作。下面是它们的作用:
-
JSZip: JSZip 是一个可以创建、读取和修改 ZIP 文件的 JavaScript 库。它允许你在客户端(浏览器)中动态生成 ZIP 文件,将多个文件或文件夹压缩成一个 ZIP 包,也可以解压已有的 ZIP 文件。在前端开发中,JSZip 可以用于在浏览器中生成和处理压缩文件,非常适合需要在客户端进行文件压缩和解压缩的场景。
-
FileSaver: FileSaver 是一个用于在客户端保存文件的 JavaScript 库。它提供了一种简单的方式来将数据保存为本地文件,通常用于在浏览器中将动态生成的内容(如图像、文档、压缩文件等)保存到用户的计算机上。FileSaver 可以将 Blob 或 File 对象保存为本地文件,支持设置文件名和文件类型,非常适合用于下载动态生成的文件。
在需要的情境中,JSZip
用于在客户端中创建和处理压缩文件,将多个文件打包成一个 ZIP 文件;而 FileSaver
则用于在客户端将生成的 ZIP 文件保存到用户的计算机中,以供用户下载和使用。这两个库通常结合使用,能够方便地处理前端的文件压缩和下载需求。
实现方法
npm i [email protected]
npm i [email protected]
页面中应用
import JSZip from 'jszip'
import FileSaver from 'file-saver'
downloadPdf () {
let title = '测试'
const flag = [
'o2dTk5MjJmcHRucmh0dDRJOUZHRlhpZmxQWFZiTlh5VUZ5VWI5az0', // 请求参数
'axaVMyeXhYbitFTWtwaFdZNTZIMzdQcTM4RE5JeFBuZENpMElJZz0',
'T2h0QS9UekxzRaZEF0QTM4V2ZQRzl0U25SVGpEcWI3YW1ITm5yWT0',
'MjFFV0xxx2SEM3RVJDZzNlUCtHRUdkcUtpU0UySHZWakFlQXBUTT0',
'b1ZnYjY1OG3433RmhDb09NS1lOOUxocVFVcEZtZXBQb1BXendWbz0'
]
const loading = this.$loading({ // 加载状态
lock: true,
text: '正在导出,请等待。。。',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
// 这里的应用场景是页面中有多个附件需要下载导出
// 创建一个 promises 数组,用于存储每个请求的 promise 循环请求
const promises = flag.map((id) => {
return axios({
url: `/frontend/api/common/downloadattchment?id=${id}&type=download`,
method: 'GET',
responseType: 'blob' // important
})
})
// 使用 Promise.all 等待所有请求完成
Promise.all(promises).then((responses) => {
var zip = new JSZip()
// 遍历每个请求的响应
responses.forEach((response, index) => {
const disposition = response.headers['content-disposition'] // 获取 HTTP 响应中头部字段 获取下载文件的文件信息
const matches = /filename="(.+?)"/.exec(disposition) // 获取文件名
const fileName = matches !== null && matches[1] ? matches[1] : `file${index + 1}`
let decodedFileName = decodeURIComponent(fileName) // URL 解码文件名
const fileType = fileName.split('.').pop() // 获取文件类型后缀名
const url = response.data
// 添加文件到压缩包中
zip.folder('报告').file(`${decodedFileName}.${fileType}`, url)
})
// 获取PDF文件并添加到压缩包中这里是单独获取base64编码格式的pdf图片数据 由base64
转换为bolb二进制文件流
getSinglePdf(title, 'pdfWarp').then((res) => {
if (res) {
let pdfBase64Str = res.split(';base64,')
let byteCharacters = atob(pdfBase64Str[1])
let byteNumbers = new Array(byteCharacters.length)
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i)
}
let byteArray = new Uint8Array(byteNumbers)
let pdfBlob = new Blob([byteArray], { type: 'application/pdf' })
zip.folder('PDF').file(`${this.reportInfo.title.slice(0, this.reportInfo.title.indexOf(':'))}.pdf`, pdfBlob)
// 生成并下载压缩文件 compression压缩模式 DEFLATE:可以压缩 STORE:不进行压缩,直接存储原始数据。 level压缩等级1-9 1最快9压缩率最高
// compressionsh: BZIP2:使用 BZIP2 算法进行压缩。BZIP2 通常提供了更高的压缩率,但可能会稍微慢一些。 LZMA:使用 LZMA 算法进行压缩。LZMA 通常提供了最高的压缩率,但也是最慢的。
zip.generateAsync({ type: 'blob', compression: 'DEFLATE', compressionOptions: { level: 9 } }, (data) => {
const { percent } = data // 导出进度
if (percent === 100) {
loading.close()
}
console.log(percent, 'percent')
}).then(function (content) {
// 使用 FileSaver 保存下载 zip 文件
FileSaver.saveAs(content, `${title}.zip`)
})
}
})
})
},
导出后效果