Ubuntu Docker环境下用html-pdf npm包生成PDF时出现EPIPE错误
在Ubuntu Docker环境下使用html-pdf npm包转换HTML到PDF时出现EPIPE错误
本地Windows和Mac系统中正常运行的HTML转PDF功能,在Ubuntu Docker环境下使用html-pdf npm包时抛出Error: write EPIPE错误,以下是详细信息:
错误日志
node:events:491 throw er; // Unhandled 'error' event ^ Error: write EPIPE at afterWriteDispatched (node:internal/stream_base_commons:160:15) at writeGeneric (node:internal/stream_base_commons:151:3) at Socket._writeGeneric (node:net:905:11) at Socket._write (node:net:917:8) at writeOrBuffer (node:internal/streams/writable:391:12) at _write (node:internal/streams/writable:332:10) at Socket.Writable.write (node:internal/streams/writable:336:10) at PDF.PdfExec [as exec] (/usr/src/node-app/node_modules/html-pdf/lib/pdf.js:156:15) at PDF.PdfToStream [as toStream] (/usr/src/node-app/node_modules/html-pdf/lib/pdf.js:59:8) at /usr/src/node-app/server.js:335:75 Emitted 'error' event on Socket instance at: at emitErrorNT (node:internal/streams/destroy:157:8) at emitErrorCloseNT (node:internal/streams/destroy:122:3) at processTicksAndRejections (node:internal/process/task_queues:83:21) { errno: -32, code: 'EPIPE', syscall: 'write'
Docker操作系统信息
uname -a [1670850844595] Linux 693e0a6af7a3 4.14.281-212.502.amzn2.x86_64 #1 SMP Thu May 26 09:52:17 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
尝试的代码
试过两个API,均出现相同错误:
- toStream方式:
htmlPdf.create(htmlContent, htmlToPdfOptions).toStream(function(err: any, stream: { pipe: (arg0: fs.WriteStream) => void; }{ stream.pipe(fs.createWriteStream('./outputDir/chatTranscript.pdf')); });
- toFile方式:
htmlPdf.create(htmlContent, htmlToPdfOptions) .toFile("newPdf.pdf", function(err: any, result: any) { if (err) { console.log("Error while generating pdf file - ",err); } // console.log("pdf file generated - ",result); // return; });
完整方法代码
async function generatePdf() { try { console.log("Inside generatePdf() ...") let HTMLFilePath = __dirname+"/pdfTemplate.html"; if (!fs.existsSync(HTMLFilePath)) { console.log("file doesn't exists"); } else { console.log("file exists: ",HTMLFilePath); } const htmlContent = fs.readFileSync(HTMLFilePath, 'utf8'); const htmlToPdfOptions = { "type": ".pdf", "height": "650px", "width": "850px", "renderDelay": 2000, }; const a = await htmlPdf.create(htmlContent, htmlToPdfOptions).toStream(function(err: any, stream: { pipe: (arg0: fs.WriteStream) => void; }{ stream.pipe(fs.createWriteStream('./outputDir/chatTranscript.pdf')); }); console.log("printing output of html stream"); console.log("a: ",a); return a; // htmlPdf.create(htmlContent, htmlToPdfOptions) // .toFile("newPdf.pdf", function(err: any, result: any) { // if (err) { // console.log("Error while generating pdf file - ",err); // } // console.log("pdf file generated - ",result); // return; // }); } catch (error) { console.log("error while converting html-to-pdf", error); } }
已做排查
- 之前容器提示缺失
libfontconfig库,已在Dockerfile中添加:
apt-get update apt-get install -y libfontconfig
- 确认PDF生成目录拥有写入权限。
解决方案
1. 补充安装PhantomJS依赖组件
html-pdf依赖PhantomJS运行,Docker的Ubuntu镜像仅安装libfontconfig不足以满足运行需求,需补充安装底层依赖:
apt-get install -y libfreetype6 libx11-6 libxext6 libxrender1 fontconfig
将上述命令添加到Dockerfile中,重新构建镜像。
2. 指定兼容的PhantomJS版本
html-pdf内置的PhantomJS版本可能与Linux内核(你的内核为4.14)不兼容,可单独安装指定版本的phantomjs-prebuilt:
npm install phantomjs-prebuilt@2.1.16 --save
然后在代码中配置html-pdf使用该本地版本:
const htmlPdf = require('html-pdf'); const phantomPath = require('phantomjs-prebuilt').path; const htmlToPdfOptions = { "type": ".pdf", "height": "650px", "width": "850px", "renderDelay": 2000, "phantomPath": phantomPath // 添加此配置项 };
3. 完善流的错误处理
原代码未监听流的错误事件,导致未捕获异常抛出,修改toStream调用逻辑:
htmlPdf.create(htmlContent, htmlToPdfOptions).toStream(function(err: any, stream: { pipe: (arg0: fs.WriteStream) => void; }{ if (err) { console.error('Stream生成错误:', err); return; } const writeStream = fs.createWriteStream('./outputDir/chatTranscript.pdf'); stream.pipe(writeStream); // 监听文件写入错误 writeStream.on('error', (err) => { console.error('PDF写入错误:', err); }); // 监听写入完成事件 writeStream.on('finish', () => { console.log('PDF生成成功'); }); });
4. 修正async/await与回调混用问题
原代码中await调用基于回调的toStream方法无效,会导致流程异常,改用Promise包装实现异步等待:
// 封装toStream为Promise function generatePdfStream(htmlContent, options) { return new Promise((resolve, reject) => { htmlPdf.create(htmlContent, options).toStream((err, stream) => { if (err) reject(err); else resolve(stream); }); }); } // 在generatePdf函数中使用 async function generatePdf() { try { // ... 省略其他代码 ... const stream = await generatePdfStream(htmlContent, htmlToPdfOptions); const writeStream = fs.createWriteStream('./outputDir/chatTranscript.pdf'); stream.pipe(writeStream); // 等待写入完成 await new Promise((resolve, reject) => { writeStream.on('finish', resolve); writeStream.on('error', reject); }); console.log('PDF生成成功'); return; } catch (error) { console.log("html转PDF失败", error); } }
内容的提问来源于stack exchange,提问作者Hemant
相关产品推荐
相关产品推荐

