# HTML to PDF 服务 (MVP版本) 基于 PuppeteerSharp + Chromium 的 HTML 转 PDF 微服务。 ## 功能特性 - ✅ HTML 内容转 PDF - ✅ URL 转 PDF - ✅ **HTML 内容转图片**(PNG/JPEG/WebP) - ✅ **URL 转图片**(支持自定义分辨率) - ✅ 浏览器实例池化(高性能) - ✅ 并发控制 - ✅ 本地文件存储(可选) - ✅ 回调机制(全局 + 请求级) - ✅ Docker 容器化部署 - ✅ 健康检查接口 ## 技术栈 - .NET 8 - PuppeteerSharp 20.2.5 - Chromium (Headless) - Docker ## 快速开始 ### 方式一:Docker Compose(推荐) ```bash # 1. 构建并启动服务 docker-compose up -d # 2. 查看日志 docker-compose logs -f pdf-service # 3. 测试服务 curl http://localhost:5000/health ``` ### 方式二:Docker 构建 ```bash # 1. 构建镜像 docker build -t html-to-pdf-service:latest . # 2. 运行容器 docker run -d \ --name pdf-service \ -p 5000:5000 \ -v $(pwd)/pdfs:/app/pdfs \ -e PdfService__BrowserPool__MaxConcurrent=5 \ html-to-pdf-service:latest # 3. 查看日志 docker logs -f pdf-service ``` ### 方式三:本地开发 ```bash # 1. 切换到 src 目录 cd src # 2. 还原依赖 dotnet restore # 3. 运行服务 cd HtmlToPdfService.Api dotnet run ``` ## API 使用示例 ### 1. HTML 内容转 PDF ```bash curl -X POST http://localhost:5000/api/pdf/convert/html \ -H "Content-Type: application/json" \ -d '{ "html": "

Hello World

这是一个测试

", "options": { "format": "A4", "landscape": false, "printBackground": true, "margin": { "top": "10mm", "right": "10mm", "bottom": "10mm", "left": "10mm" } }, "saveLocal": true }' \ --output test.pdf ``` ### 2. URL 转 PDF ```bash curl -X POST http://localhost:5000/api/pdf/convert/url \ -H "Content-Type: application/json" \ -d '{ "url": "https://www.baidu.com", "waitUntil": "networkidle2", "timeout": 30000, "options": { "format": "A4" } }' \ --output baidu.pdf ``` ### 3. 带回调的转换 ```bash curl -X POST http://localhost:5000/api/pdf/convert/html \ -H "Content-Type: application/json" \ -d '{ "html": "

Test with Callback

", "callback": { "url": "https://your-callback-server.com/webhook", "headers": { "X-API-Key": "your-api-key" }, "includePdfData": false }, "saveLocal": true }' \ --output test.pdf ``` ### 4. 下载已生成的 PDF ```bash curl http://localhost:5000/api/pdf/download/{requestId} \ --output downloaded.pdf ``` ### 5. HTML 转图片 ```bash # 基本用法 curl -X POST http://localhost:5000/api/image/convert/html \ -H "Content-Type: application/json" \ -d '{ "html": "

转成图片

", "options": { "format": "png", "fullPage": true, "width": 1920, "height": 1080 } }' \ --output screenshot.png # JPEG 格式带质量设置 curl -X POST http://localhost:5000/api/image/convert/html \ -H "Content-Type: application/json" \ -d '{ "html": "

高质量图片

", "options": { "format": "jpeg", "quality": 90, "width": 1920, "height": 1080 } }' \ --output screenshot.jpg ``` ### 6. URL 转图片 ```bash curl -X POST http://localhost:5000/api/image/convert/url \ -H "Content-Type: application/json" \ -d '{ "url": "https://www.baidu.com", "options": { "format": "png", "fullPage": true, "width": 1920, "height": 1080 } }' \ --output baidu.png ``` ### 7. 健康检查 ```bash curl http://localhost:5000/health ``` #### 图片转换参数说明 | 参数 | 说明 | 默认值 | |------|------|--------| | `format` | 图片格式:png, jpeg, webp | png | | `quality` | 图片质量 (0-100),仅 jpeg/webp | 90 | | `fullPage` | 是否全页截图 | true | | `width` | 视口宽度(像素) | 1920 | | `height` | 视口高度(像素) | 1080 | | `omitBackground` | 是否透明背景(仅 png) | false | | `clip` | 截图区域(x, y, width, height) | null | ``` 响应示例: ```json { "status": "Healthy", "timestamp": "2024-12-10T10:30:00Z", "browserPool": { "totalInstances": 3, "availableInstances": 2, "maxInstances": 10 }, "queue": { "currentTasks": 1, "maxConcurrent": 5 } } ``` ## 配置说明 主要配置在 `appsettings.json` 中: ```json { "PdfService": { "BrowserPool": { "MaxInstances": 10, // 最大浏览器实例数 "MinInstances": 2, // 最小保持实例数(预热) "MaxConcurrent": 5, // 最大并发转换数 "AcquireTimeout": 30000 // 获取实例超时(毫秒) }, "Storage": { "SaveLocalCopy": true, // 是否保存本地副本 "LocalPath": "/app/pdfs", // 存储路径 "RetentionHours": 24 // 文件保留时间(小时) }, "Callback": { "Enabled": true, // 是否启用回调 "DefaultUrl": "", // 默认回调 URL "Timeout": 30000, // 回调超时(毫秒) "IncludePdfData": false // 是否在回调中包含 PDF Base64 } } } ``` ### 环境变量配置 可以通过环境变量覆盖配置: ```bash export PdfService__BrowserPool__MaxInstances=20 export PdfService__BrowserPool__MaxConcurrent=10 export PdfService__Storage__SaveLocalCopy=false export PdfService__Callback__DefaultUrl=https://your-callback.com/webhook ``` ## 回调格式 转换完成后,服务会向配置的回调 URL 发送 POST 请求: ```json { "requestId": "uuid-generated", "status": "success", "timestamp": "2024-12-10T10:30:00Z", "duration": 1523, "result": { "fileSize": 102400, "downloadUrl": "http://service/api/pdf/download/{requestId}", "pdfBase64": "JVBERi0xLjQK...", // 如果 includePdfData: true "expiresAt": "2024-12-11T10:30:00Z" }, "source": { "type": "html", "content": "...", "options": {} }, "error": null } ``` 失败时: ```json { "requestId": "uuid-generated", "status": "failed", "timestamp": "2024-12-10T10:30:00Z", "duration": 523, "error": { "code": "CONVERSION_FAILED", "message": "页面加载超时", "details": "..." } } ``` ## 性能参数 | 指标 | 建议值 | |------|--------| | 内存 | 1-2GB | | CPU | 1-2 核心 | | 并发数 | 5-10 | | 单次转换时间 | 0.5-5秒 | ## 故障排查 ### 1. Chromium 启动失败 确保 Docker 容器有足够权限: ```bash docker run --cap-add=SYS_ADMIN ... ``` 或使用 `--no-sandbox` 参数(已默认配置)。 ### 2. 中文字体显示问题 Dockerfile 已包含中文字体安装: - fonts-wqy-zenhei - fonts-wqy-microhei ### 3. 内存不足 调整 Docker 容器内存限制: ```yaml deploy: resources: limits: memory: 4G ``` ## 开发计划 - [x] 核心转换功能 - [x] 浏览器池化 - [x] 回调机制 - [x] Docker 部署 - [ ] 任务异步处理 - [ ] 认证授权 - [ ] 管理后台 - [ ] Kubernetes 支持 ## 许可证 MIT License ## 联系方式 如有问题或建议,请提交 Issue。