生成PDF文件:从html2canvas和jsPdf渲染到Puppeteer矢量图
刚刚实现而已:第一次明白,双击或file:///
打开html
文件,居然和从localhost:3000
打开同一个html
文件有本质的区别。
字体居然还能以Base64代码嵌入到网页,只是太大太笨。
需要安装node.js
,npm
安装更多依赖:
npm init -y
npm install express puppeteer uuid cors
需要管理员在命令行:
npm start
或
node server.js
(后台、后端,也涉及很多繁琐的设置)
如果不是有大语言模型手把手交,效率会低不少。
反复测试,仍不完美。但server.js
应该是可以固定下来了:
const express = require('express');
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs').promises;
const { v4: uuidv4 } = require('uuid');
const cors = require('cors');
const app = express();
app.use(express.static('public'));
const port = 3000;
// 配置 CORS
app.use(cors({
origin: 'http://localhost:3000', // 明确允许客户端来源
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type']
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.send('服务器运行正常!请访问 /index.html 或点击“打印到 PDF”按钮生成 PDF。');
});
app.post('/generatepdf', async (req, res) => {
console.log('Received request to generate PDF');
const { html } = req.body;
if (!html) {
console.error('Missing HTML content in request body');
return res.status(400).send('Missing HTML content');
}
try {
console.log('Launching Puppeteer...');
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
console.log('Puppeteer launched successfully');
const page = await browser.newPage();
console.log('Setting page content...');
await page.setContent(html, { waitUntil: 'networkidle0' });
console.log('Page content set');
console.log('Generating PDF...');
const pdfBuffer = await page.pdf({
format: 'A4',
printBackground: true,
preferCSSPageSize: true
});
console.log('PDF buffer size:', pdfBuffer.length);
await browser.close();
console.log('PDF generated successfully');
// 保存 PDF 文件用于调试
const filename = `jingyesi-output-${uuidv4()}.pdf`;
await fs.writeFile(path.join(__dirname, filename), pdfBuffer);
console.log(`PDF saved to ${filename} for debugging`);
// 设置响应头并发送 PDF(使用二进制发送)
res.set({
'Content-Type': 'application/pdf',
'Content-Length': pdfBuffer.length,
'Content-Disposition': 'attachment; filename="jingyesi.pdf"'
});
res.end(pdfBuffer, 'binary'); // 使用 res.end 确保二进制数据发送
} catch (error) {
console.error('Failed to generate PDF:', error);
res.status(500).send('Failed to generate PDF: ' + error.message);
}
});
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
要保持 localhost:3000
后台服务器一直开启状态。访问本地其它资源的虚拟网页仍然要http-server --c-1 -cors
另外开或者修改地址之后也从同一个服务器指向的文件夹实现
不完美的地方主要是,Puppeteer
对嵌入字体的支持比较弱,Base64代码把整个字体文件打包进去之外太笨拙,引用网络字体似乎效果不理想。
尝试修改排版,但下面这个显然效果不佳: