生产环境下如何用vue-pdf-embed展示静态PDF URL
Vue生产环境下Dialog无法展示PDF问题解决方案
问题概述
开发环境中使用vue-pdf-embed能正常在Dialog里展示PDF,但生产环境完全无法显示。父组件通过axios获取PDF转为Blob URL,子组件接收URL渲染PDF。
父组件核心代码
async function openDialog(index: number) { isLoading.value = true; const selectedEbook = listEbook.value[index]; const originalUrl = selectedEbook.url; if (!originalUrl) { console.warn("URL tidak tersedia untuk item ini"); isLoading.value = false; return; } const isDev = import.meta.env.MODE === "development"; const fileUrl = isDev ? originalUrl.replace("https://main-url.com", "/api-pdf") : originalUrl; if (!fileUrl) return; try { const response = await axios.get(fileUrl, { responseType: "blob", }); if (!response) throw new Error("Gagal fetch file PDF"); if (selectedBlobUrl.value) { URL.revokeObjectURL(selectedBlobUrl.value); } // 冗余的Blob处理逻辑 if (selectedEbook.icon != "pi-file-pdf") { const blob = new Blob([response.data], { type: "application/pdf" }); selectedBlobUrl.value = URL.createObjectURL(blob); } else { const url = URL.createObjectURL( new Blob([response.data], { type: "application/pdf", }) ); selectedBlobUrl.value = url; } console.log(selectedBlobUrl.value); pdfDialog.value = true; } catch (err) { console.error("Gagal membuka PDF:", err); } finally { isLoading.value = false; } }
子组件核心代码
<template> <Dialog v-model:visible="visible" modal header="Lihat Dokumen" :style="{ width: '100%', height: '100%' }" :breakpoints="{ '1199px': '75vw', '575px': '90vw' }" > <VuePdfEmbed annotation-layer text-layer :source="props.url" class="shadow-3" /> </Dialog> </template> <script setup lang="ts"> import { computed, watch } from "vue"; import VuePdfEmbed from "vue-pdf-embed"; import "vue-pdf-embed/dist/styles/annotationLayer.css"; import "vue-pdf-embed/dist/styles/textLayer.css"; const props = defineProps<{ url: string | null; modelValue: boolean; }>(); const emits = defineEmits<{ (e: "update:modelValue", value: boolean): void; }>(); const visible = computed({ get: () => props.modelValue, set: (value) => emits("update:modelValue", value), }); watch( () => props.url, (value) => { if (value) { console.log(value); } } ); </script>
排查与解决步骤
1. 检查生产环境CORS配置
生产环境直接访问originalUrl,如果该URL所在服务器未配置跨域允许(Access-Control-Allow-Origin),axios会无法获取Blob资源,导致生成的Blob URL无效。
- 解决方案:联系后端在PDF文件服务器添加跨域头,允许你的生产域名访问;如果是同域部署,调整
fileUrl为相对路径;或通过Nginx反向代理转发PDF请求,规避跨域问题。
2. 简化冗余的Blob处理逻辑
父组件中两个分支的Blob处理逻辑完全一致,冗余代码可能导致潜在错误,合并为统一逻辑:
// 替换原if-else代码 const blob = new Blob([response.data], { type: "application/pdf" }); selectedBlobUrl.value = URL.createObjectURL(blob);
3. 验证生产环境fileUrl有效性
在生产环境打开控制台,打印fileUrl确认是否可直接访问:
- 如果
fileUrl无法在浏览器直接打开,说明URL本身无效,需要检查生产环境的地址配置、FTP/API服务是否正常。
4. 确保vue-pdf-embed正确打包
检查package.json中vue-pdf-embed是否在dependencies而非devDependencies中,避免生产打包时被排除:
{ "dependencies": { "vue-pdf-embed": "^x.x.x" } }
5. 延迟Dialog打开时机
确保Blob URL生成完成后再打开Dialog,避免vue-pdf-embed接收空URL:
// 生成Blob URL后再打开Dialog selectedBlobUrl.value = URL.createObjectURL(blob); // 加个微任务确保URL已生效 await nextTick(); pdfDialog.value = true;
(需要在函数顶部导入nextTick:import { nextTick } from 'vue')
6. 完善Blob URL生命周期管理
在Dialog关闭时释放Blob URL,避免内存泄漏,同时确保下次打开时重新生成有效URL:
- 父组件监听Dialog关闭事件:
watch(pdfDialog, (newVal) => { if (!newVal && selectedBlobUrl.value) { URL.revokeObjectURL(selectedBlobUrl.value); selectedBlobUrl.value = null; } });
额外调试技巧
- 在生产环境打开浏览器控制台,查看Network面板中PDF请求的状态码,确认是否有403/404等错误;
- 查看Console面板是否有跨域、Blob生成失败等报错信息;
- 尝试直接在生产环境页面中嵌入生成的Blob URL,确认URL本身是否有效。
内容的提问来源于stack exchange,提问作者Febryan Akhdani
相关产品推荐
相关产品推荐

