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

Next.js 13中点击按钮触发POST请求下载PDF失败问题

解决Next.js 13中POST请求触发PDF下载的问题

问题核心在于fetch请求不会自动识别Content-Disposition: attachment响应头:浏览器直接导航(比如<Link>发起的GET请求)会自动触发下载,但脚本发起的fetch请求需要手动处理返回的Blob数据才能完成下载。另外你的客户端请求头存在错误——POST的body是JSON格式,却设置了Content-type: application/pdf,这会导致后端无法正确解析请求体,需要先修正这个问题。

修改客户端组件代码

更新generatePdf函数,在获取响应后手动处理Blob并触发下载:

function generatePdf() {
  fetch("/api/generate-pdf", {
    method: "POST",
    headers: {
      // 修正请求头:发送JSON数据需用该类型
      "Content-Type": "application/json",
    },
    body: JSON.stringify(store),
  })
  .then(async (res) => {
    if (!res.ok) throw new Error("PDF生成请求失败");
    // 将响应转换为Blob对象
    const blob = await res.blob();
    // 创建临时下载URL
    const downloadUrl = window.URL.createObjectURL(blob);
    // 创建临时a标签触发下载
    const link = document.createElement("a");
    link.href = downloadUrl;
    // 设置文件名(也可从响应头动态解析)
    link.download = "pac.pdf";
    document.body.appendChild(link);
    link.click();
    // 清理临时资源
    link.remove();
    window.URL.revokeObjectURL(downloadUrl);
  })
  .catch((err) => {
    console.error("生成PDF出错:", err);
    // 可在此添加用户可见的错误提示,比如alert或组件提示
  });
}

<Button onClick={generatePdf} type="button">
    Generate PDF
</Button>

补充:动态解析后端返回的文件名

如果不想在客户端硬编码文件名,可以从响应头中解析后端返回的Content-Disposition字段:

// 在获取blob后添加这段代码
const dispositionHeader = res.headers.get("Content-Disposition");
let filename = "pac.pdf";
if (dispositionHeader) {
  const filenameMatch = dispositionHeader.match(/filename="?([^"]+)"?/);
  if (filenameMatch?.[1]) {
    filename = filenameMatch[1];
  }
}
link.download = filename;

为什么GET请求能用?

当使用<Link>或直接在地址栏访问GET接口时,浏览器是直接导航到目标URL,会自动识别响应头里的Content-Disposition: attachment并触发下载流程;而fetch属于AJAX请求,是脚本发起的异步请求,浏览器不会自动处理下载逻辑,必须手动触发。

内容的提问来源于stack exchange,提问作者WindCheck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:32:38