Express.js+EJS项目PDF下载异常:获undefined文本文件问题排查
Express下载PDF返回undefined文本文件的问题
使用Express.js框架实现服务器文件下载,前端EJS页面点击a标签后,未触发目标PDF下载,反而得到内容为“undefined”的文本文件,相关代码及问题修复如下:
客户端代码
HTML(EJS)
<a href="javascript:void(0);" class="download-file" data-id="<%= book._id%>">Download Book</a>
前端脚本
const getFile = document.querySelector("a.download-file"); getFile.addEventListener("click", () => { const endPoint = `/pages/${getFile.dataset.id}`; if (confirm(`Confirm PDF download to your computer`)) { fetch(endPoint, {method: "GET"}) .then((response) => response.blob()) .then((res) => { console.log(res) const url = window.URL.createObjectURL(new Blob([res.data])); const link = document.createElement("a"); link.href = url; link.setAttribute("download", "Pdf Book"); document.body.appendChild(link); link.click(); }) .catch((err) => console.log("Error:", err)); } else { return; } });
后端代码
路由
bookRouter.get("/:id", bookController.downloadSingleBook);
控制器
const downloadSingleBook = (req, res) => { let bookID = req.params.id; Book.findById(bookID) .then((response) => { const file = path.resolve(response.bookfile); res.download(file); }) .catch((err) => { console.log(err); }); };
问题原因及修复
1. 前端Blob处理错误
response.blob()返回的是完整Blob对象,不存在.data属性,你错误访问res.data导致传入Blob的内容为undefined,因此生成的文件内容就是undefined。
修复后的前端脚本:
const getFile = document.querySelector("a.download-file"); getFile.addEventListener("click", () => { const endPoint = `/pages/${getFile.dataset.id}`; if (confirm(`Confirm PDF download to your computer`)) { fetch(endPoint, {method: "GET"}) .then((response) => { // 先判断响应是否成功 if (!response.ok) throw new Error("File download failed"); return response.blob(); }) .then((blob) => { const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; // 可从响应头获取服务器返回的文件名,或自定义 const filename = response.headers.get('content-disposition')?.split('filename=')[1] || "Pdf Book.pdf"; link.setAttribute("download", filename); document.body.appendChild(link); link.click(); // 释放URL对象避免内存泄漏 window.URL.revokeObjectURL(url); document.body.removeChild(link); }) .catch((err) => console.log("Error:", err)); } });
2. 后端潜在问题排查
- 确保
response.bookfile是正确的文件路径,path.resolve处理后能指向真实存在的PDF文件 - 添加文件存在性检查,避免无效路径导致的静默错误:
const fs = require('fs'); const downloadSingleBook = (req, res) => { let bookID = req.params.id; Book.findById(bookID) .then((response) => { const file = path.resolve(response.bookfile); if (!fs.existsSync(file)) { return res.status(404).send("Target file not found"); } res.download(file); }) .catch((err) => { console.log(err); res.status(500).send("Server error"); }); };
3. 简化方案(可选)
无需使用fetch,直接让a标签跳转即可实现下载,代码更简洁:
<a href="/pages/<%= book._id%>" class="download-file" download>Download Book</a>
内容的提问来源于stack exchange,提问作者Aurther
相关产品推荐
相关产品推荐

