const express = require('express'); const { chromium } = require('playwright'); const cors = require('cors'); const bodyParser = require('body-parser'); const path = require('path'); const fs = require('fs'); const app = express(); const PORT = process.env.PORT || 3000; // 中间件 app.use(cors()); app.use(bodyParser.json({ limit: '50mb' })); app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' })); // 确保输出目录存在 const outputDir = path.join(__dirname, 'output'); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } class PdfService { constructor() { this.browser = null; } async initialize() { if (this.browser) return; this.browser = await chromium.launch({ headless: true, args: [ '--no-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--disable-web-security' ] }); console.log('Playwright浏览器初始化成功'); } async generatePdf(options) { if (!this.browser) { await this.initialize(); } const context = await this.browser.newContext(); const page = await context.newPage(); try { const { html, url, landscape = false, format = 'A4', margin = { top: 20, right: 20, bottom: 20, left: 20 }, printBackground = true, timeout = 60000 } = options; page.setDefaultTimeout(timeout); if (url) { console.log(`正在生成PDF: ${url}`); await page.goto(url, { waitUntil: 'networkidle', timeout: timeout }); } else if (html) { console.log('正在转换HTML到PDF'); await page.setContent(html, { waitUntil: 'networkidle', timeout: timeout }); } else { throw new Error('必须提供html或url参数'); } // 生成PDF const pdfBuffer = await page.pdf({ landscape, format, margin, printBackground, preferCSSPageSize: false }); return pdfBuffer; } finally { await context.close(); } } async close() { if (this.browser) { await this.browser.close(); } } } const pdfService = new PdfService(); // 健康检查端点 app.get('/health', async (req, res) => { try { await pdfService.initialize(); res.json({ status: 'healthy', service: 'HTML to PDF Service', timestamp: new Date().toISOString() }); } catch (error) { res.status(503).json({ status: 'unhealthy', error: error.message }); } }); // 通过URL生成PDF app.get('/generate', async (req, res) => { try { const { url, download = 'false' } = req.query; if (!url) { return res.status(400).send(`

PDF生成服务

请提供URL参数,例如:

/generate?url=https://example.com `); } const pdfBuffer = await pdfService.generatePdf({ url: url, timeout: 60000 }); const filename = `document-${Date.now()}.pdf`; res.setHeader('Content-Type', 'application/pdf'); if (download === 'true') { res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); } else { res.setHeader('Content-Disposition', `inline; filename="${filename}"`); } res.send(pdfBuffer); } catch (error) { console.error('PDF生成错误:', error); res.status(500).send(`

PDF生成失败

错误信息: ${error.message}

返回首页 `); } }); // 通过HTML内容生成PDF - POST接口 app.post('/generate/html', async (req, res) => { try { const { html, download = false, filename = `document-${Date.now()}.pdf` } = req.body; if (!html) { return res.status(400).json({ success: false, error: 'HTML内容不能为空' }); } console.log('正在通过HTML内容生成PDF'); const pdfBuffer = await pdfService.generatePdf({ html: html, timeout: 60000 }); res.setHeader('Content-Type', 'application/pdf'); if (download) { res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); } else { res.setHeader('Content-Disposition', `inline; filename="${filename}"`); } res.send(pdfBuffer); } catch (error) { console.error('HTML内容转PDF错误:', error); res.status(500).json({ success: false, error: error.message }); } }); // 通过HTML内容生成PDF - GET接口(表单提交) app.get('/generate/html-form', (req, res) => { res.send(` HTML转PDF

HTML内容转PDF

返回首页
`); }); // 首页 app.get('/', (req, res) => { res.send(` PDF生成服务

PDF生成服务

🔗 URL转PDF

通过网页URL生成PDF文档




📝 HTML内容转PDF

通过HTML代码直接生成PDF文档

使用HTML转PDF工具

API接口说明

URL转PDF: GET /generate?url=https://example.com

HTML转PDF: POST /generate/html

// 请求示例
{
    "html": "<h1>Hello PDF</h1>",
    "download": true,
    "filename": "document.pdf"
}
                    
`); }); // 优雅关闭 process.on('SIGINT', async () => { console.log('正在关闭服务...'); await pdfService.close(); process.exit(0); }); process.on('SIGTERM', async () => { console.log('收到终止信号,正在关闭服务...'); await pdfService.close(); process.exit(0); }); // 启动服务 app.listen(PORT, async () => { console.log(`HTML转PDF服务运行在端口 ${PORT}`); console.log(`访问地址: http://localhost:${PORT}`); console.log(`URL转PDF: http://localhost:${PORT}/generate?url=https://example.com`); console.log(`HTML转PDF表单: http://localhost:${PORT}/generate/html-form`); }); module.exports = app;