Express+Puppeteer生成PDF邮件附件Linux服务器报错求助
Puppeteer在Linux服务器启动失败的解决方案
问题背景
在Express.js项目中,通过Puppeteer实时生成PDF并作为邮件附件发送,该功能在Windows本地环境正常运行,但部署到Linux服务器时出现「启动浏览器进程失败」的错误,且需求为不在服务器存储PDF文件。
用户代码
async function generatePDF(templatePath, params) { try { const htmlTemplate = await ejs.renderFile(templatePath, params); const browser = await puppeteer.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--disable-software-rasterizer' ], dumpio: true, }); const page = await browser.newPage(); await page.setContent(htmlTemplate, { waitUntil: 'domcontentloaded' }); const pdfBuffer = await page.pdf({ format: 'A4', printBackground: true, }); await browser.close(); return pdfBuffer; } catch (error) { throw new Error(`PDF generation failed: ${error.message}`); } } exports.process = async (email, name) => { try { const emailBodyParams = { }; const invitationParams = { }; // Generate PDF buffers const emailBody = await ejs.renderFile(path.join(__dirname, 'templates', 'invitation.html'), emailBodyParams); const invitationBuffer = await generatePDF(path.join(__dirname, 'templates', 'card.html'), invitationParams); const mailOptions = { from: '"No Reply" <no-reply@test.org>', to: email, subject: 'Your invitation', html: emailBody, attachments: [ { filename: 'invitation_card.pdf', content: invitationBuffer, } ], }; // Send the email transporter.sendMail(mailOptions, (error, info) => { if (error) { throw new Error(error); } console.log(info); return true; }); } catch (err) { throw new Error(err); } }
报错信息
You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection: Error: Error: PDF generation failed: Failed to launch the browser process! TROUBLESHOOTING: https://pptr.dev/troubleshooting at exports.processEmail (................emailProcessService.js:69:9) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
解决方案
1. 安装Chrome依赖库
Linux服务器默认缺少Chrome/Chromium运行所需的系统依赖,根据发行版执行对应命令:
- Debian/Ubuntu:
sudo apt-get update sudo apt-get install -y libnss3 libatk-bridge2.0-0 libdrm-dev libxkbcommon-dev libgbm-dev libasound-dev libatspi2.0-0 libxshmfence-dev
- CentOS/RHEL:
sudo yum install -y pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64
2. 手动指定Chrome可执行路径
Puppeteer可能无法自动定位到浏览器可执行文件,在launch配置中添加executablePath:
const browser = await puppeteer.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--disable-software-rasterizer' ], dumpio: true, executablePath: '/usr/bin/google-chrome' // 用`which google-chromium`或`which chrome`查找实际路径 });
3. 缓解内存与进程限制
Linux服务器的/dev/shm临时空间有限,可通过以下参数优化:
const browser = await puppeteer.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--disable-software-rasterizer', '--disable-features=VizDisplayCompositor', '--single-process' // 单进程模式减少内存占用 ], dumpio: true, });
4. 修复邮件发送的Promise捕获问题
原代码中transporter.sendMail使用回调形式,在async函数中会导致未捕获的Promise拒绝,改为Promise封装:
// 替换原邮件发送代码 await new Promise((resolve, reject) => { transporter.sendMail(mailOptions, (error, info) => { if (error) { reject(error); } else { console.log(info); resolve(true); } }); });
5. 升级Puppeteer版本
旧版Puppeteer可能与服务器上的浏览器版本不兼容,执行升级命令:
npm update puppeteer
内容的提问来源于stack exchange,提问作者kasfik
相关产品推荐
相关产品推荐

