求助:Node.js环境下无需无头浏览器实现HTML转PDF并上传S3
可行的HTML转PDF并上传S3的替代方案
1. wkhtmltopdf + Node.js封装库
wkhtmltopdf是基于WebKit的轻量命令行工具,专门处理HTML转PDF,依赖比Chromium小得多,服务器环境适配性好,能完美配合pm2使用。
- 可以直接调用系统命令生成PDF后转Buffer,也用Node.js的
wkhtmltopdf-node这类封装库直接获取Buffer输出。 - 操作流程:
- 服务器通过包管理器安装wkhtmltopdf(比如Ubuntu用
apt install wkhtmltopdf,CentOS用yum install wkhtmltopdf) - Node.js中生成PDF Buffer:
const wkhtmltopdf = require('wkhtmltopdf'); const htmlContent = '<h1>测试PDF内容</h1>'; const pdfBuffer = await new Promise((resolve, reject) => { wkhtmltopdf(htmlContent, { output: 'buffer' }, (err, buffer) => { if (err) reject(err); else resolve(buffer); }); }); - 用AWS SDK将
pdfBuffer上传至S3即可
- 服务器通过包管理器安装wkhtmltopdf(比如Ubuntu用
2. html-pdf(基于PhantomJS)
html-pdf是Node.js专属库,底层依赖PhantomJS,虽然PhantomJS已停止维护,但对简单HTML转PDF场景依然稳定,依赖安装简单,pm2启动的Node.js进程能正常调用。
- 示例代码:
const pdf = require('html-pdf'); const htmlContent = '<div>示例PDF内容</div>'; const options = { format: 'A4' }; const pdfBuffer = await new Promise((resolve, reject) => { pdf.create(htmlContent, options).toBuffer((err, buffer) => { if (err) reject(err); else resolve(buffer); }); }); // 上传S3代码略
3. 修复Puppeteer的pm2兼容问题
如果不想换工具,也能解决Puppeteer和pm2的冲突:
- 启动Puppeteer时添加沙箱禁用参数,同时指定系统已安装的Chromium路径(避免自带的Chromium依赖问题):
const puppeteer = require('puppeteer'); const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: '/usr/bin/chromium-browser' // 替换成服务器上Chromium的实际路径 }); const page = await browser.newPage(); await page.setContent(htmlContent); const pdfBuffer = await page.pdf({ format: 'A4' }); await browser.close(); - 确保服务器安装了Chromium的依赖库(比如libx11、libxcomposite等),pm2启动时环境变量正常。
4. Playwright替代Puppeteer
Playwright是微软推出的自动化工具,支持多浏览器,服务器环境兼容性比Puppeteer更好,能直接生成PDF Buffer。
- 安装时可选择只安装Chromium,或直接调用系统已安装的浏览器,减少依赖体积。
- 示例代码:
const { chromium } = require('playwright'); const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] }); const page = await browser.newPage(); await page.setContent(htmlContent); const pdfBuffer = await page.pdf({ format: 'A4' }); await browser.close();
内容的提问来源于stack exchange,提问作者dnfnfn1515
相关产品推荐
相关产品推荐

