Node+Vue项目中用pdfkit生成PDF,blob-stream报Blob构造函数错误求助
解决方案:Node服务端生成PDF并实现邮件发送+客户端预览
问题根源
blob-stream 是为浏览器环境设计的工具,Node.js 运行时没有内置 Blob 构造函数,直接使用会抛出你遇到的「Blob is not a constructor/function」错误。我们需要改用 Node.js 原生的流处理方案,同时满足邮件发送和客户端预览两个需求。
实现步骤与代码修改
- 用 Node 原生流捕获PDF输出:使用
PassThrough流收集pdfkit的输出,转为Buffer(Buffer是Node端处理二进制数据的标准方式)。 - 复用Buffer实现双需求:同一个Buffer既可以作为邮件附件发送,也能返回给客户端用于预览。
- 客户端设置响应类型:前端请求时指定
responseType: 'blob',才能正确解析服务端返回的二进制PDF数据。
修改后的服务端代码
const pdfkit = require('pdfkit'); const nodemailer = require('nodemailer'); const { PassThrough } = require('stream'); // 完善邮件发送函数,新增PDF Buffer参数 async function sendMailer(email, pdfBuffer) { // 这里替换成你的邮件服务配置(比如QQ/163/Gmail的SMTP信息) const transporter = nodemailer.createTransport({ host: 'smtp.example.com', port: 587, secure: false, auth: { user: 'your-email@example.com', pass: 'your-email-password' } }); await transporter.sendMail({ from: 'your-email@example.com', to: email, subject: '生成的PDF文档', text: '附件是你请求的PDF文件', attachments: [ { filename: 'document.pdf', content: pdfBuffer, contentType: 'application/pdf' } ] }); } app.post('/', async (req, res) => { try { const doc = new pdfkit(); const passThroughStream = new PassThrough(); const pdfChunks = []; // 收集PDF流的二进制片段 passThroughStream.on('data', (chunk) => pdfChunks.push(chunk)); passThroughStream.on('end', async () => { const pdfBuffer = Buffer.concat(pdfChunks); // 先发送邮件 await sendMailer(req.body.email, pdfBuffer); // 再返回PDF给客户端,支持浏览器直接预览 res.setHeader('Content-Type', 'application/pdf'); // 用inline表示浏览器预览,改成attachment则触发下载 res.setHeader('Content-Disposition', 'inline; filename="document.pdf"'); res.send(pdfBuffer); }); // 写入PDF内容 doc.text('hallo!!!!', { fontSize: 50 }); doc.pipe(passThroughStream); doc.end(); } catch (err) { console.error(err); res.status(500).send('PDF生成或发送失败'); } });
Vue客户端预览代码示例
// 以axios为例,发送请求并预览PDF async function getAndPreviewPDF(userEmail) { try { const response = await axios.post('/', { email: userEmail }, { responseType: 'blob' // 必须指定,否则会解析成乱码 }); // 创建Blob URL并打开预览 const blobUrl = URL.createObjectURL(response.data); window.open(blobUrl); // 可选:如果要在页面内嵌入预览,用iframe // const iframe = document.createElement('iframe'); // iframe.style.width = '100%'; // iframe.style.height = '800px'; // iframe.src = blobUrl; // document.querySelector('.pdf-preview-container').appendChild(iframe); } catch (error) { console.error('请求PDF失败:', error); } }
关键注意事项
- 邮件服务配置需要替换成你实际的SMTP信息,不同邮箱的SMTP地址/端口可能不同。
- 服务端返回时的
Content-Disposition头:inline让浏览器直接预览,attachment则触发下载,可根据需求切换。 - 客户端必须设置
responseType: 'blob',否则axios会把二进制PDF数据当成字符串解析,导致预览失败。
内容的提问来源于stack exchange,提问作者שמעון פוקס
相关产品推荐
相关产品推荐

