You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产环境下如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 11:10:00