VueJS结合GraphQL实现PDF下载时首次点击触发网络错误如何解决
问题根本原因
当前代码的核心问题是异步逻辑处理错误:downloadFile 内部的axios请求是异步执行的,你使用固定1秒等待的方式完全不可靠:
- 首次点击时请求还没返回结果,
this.file_info还没有被赋值,就调用了下载逻辑,自然报错 - 文件越大,接口返回耗时越长,固定等待的时间就越难匹配请求耗时,所以大文件需要多次点击才能碰巧赶上请求完成的时间点
修复方案
1. 核心逻辑调整
- 让
downloadFile返回axios的Promise实例,这样可以用await精准等待请求完成,不用固定时长等待 - 增加下载中状态锁,避免用户重复点击触发多次请求
- 修正下载的MIME类型,PDF文件应该用
application/pdf而非text/plain,避免下载后文件无法正常打开 - 增加错误捕获逻辑,接口出错时可以直接给用户提示,不用等超时
2. 修改后的完整代码
// 提前在data中初始化状态:isDownloading: false, download_file_name: '' sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); }, // 改为返回Promise实例 downloadFile() { const vm = this; vm.count ++; return axios.post("http://0.0.0.0/graphql", { query: `mutation download_doc($object_path:String!) { download_doc(object_path:$object_path) { file_name encoded_file } }`, variables : { object_path: this.object_path } }) .then(response => { vm.file_info = response.data.data.download_doc.encoded_file // 存储后端返回的原始文件名,比直接用object_path更合理 vm.download_file_name = response.data.data.download_doc.file_name }) .catch(err => { console.error('下载接口请求失败', err) alert('文件下载失败,请稍后重试') throw err }) }, downloadBase64File(base64Data, fileName) { // 修正PDF对应的MIME类型 const linkSource = `data:application/pdf;base64,${base64Data}`; const downloadLink = document.createElement("a"); downloadLink.href = linkSource; downloadLink.download = fileName; downloadLink.click(); // 移除创建的DOM节点,避免内存泄漏 downloadLink.remove() }, async download() { // 重复点击拦截 if(this.isDownloading) return this.isDownloading = true try { // 等待请求真正完成,不需要固定时长盲等 await this.downloadFile(); this.downloadBase64File(this.file_info, this.download_file_name || this.object_path); await this.sleep(1000); if (this.count >= 2) { this.clearForm() } } catch(err) { console.error('下载流程出错', err) } finally { // 无论成功失败都重置下载状态 this.isDownloading = false } }
3. 额外优化建议
如果你的PDF文件体积较大,base64编码会让文件体积膨胀30%左右,传输效率很低。可以让后端直接返回文件流,前端通过blob方式下载,性能会好很多,也不会出现大文件base64解析失败的问题。
内容的提问来源于stack exchange,提问作者Kelly
相关产品推荐
相关产品推荐

