项目七 PDF 处理工具
区分 HTML 转 PDF、上传后异步处理和重型原生任务,建立 R2、Queue 与状态接口。
编辑与核验:橙宝书编辑团队 ·
完成标准
HTML 或 URL 可以生成 PDF;上传文件进入 R2 后创建异步任务;用户可查询 queued、running、done、failed;重复消息不会生成冲突结果;大文件、加密文件、超时和处理器失败都有清晰边界。
前置条件与运行随书示例
随书示例先实现一个真实且边界清晰的 html-to-pdf 操作。单元测试完全替换 Browser Run binding,不需要账号也不消耗远程额度:
node --test examples/pdf-tool/test/index.test.mjs应看到 9 个测试通过,覆盖租户状态查询、Queue 最小消息、危险 HTML 拒绝、D1 失败补偿、PDF 签名、确定性输出 key、重复消费、重试与最终失败。完整 Worker 还需要 D1、R2、主 Queue、dead-letter Queue 与 Browser Run;browser.remote 已按当前 Quick Actions 要求设为 true,因此本地启动完整流程也需要 Cloudflare 登录并消耗 Browser Run 用量。
cp examples/pdf-tool/.dev.vars.example examples/pdf-tool/.dev.vars
pnpm wrangler d1 migrations apply orange-book-pdf-jobs --local --config examples/pdf-tool/wrangler.jsonc
pnpm wrangler dev --config examples/pdf-tool/wrangler.jsonc处理能力边界
示例把安全 HTML 转成 PDF;它没有声称能合并、拆分、OCR 或解析任意上传 PDF。这些任务必须接入经过独立限制与审计的 Container 或外部处理器。
先把 PDF 任务分三类
| 任务 | Cloudflare 起点 | 请求模型 |
|---|---|---|
| HTML/URL 生成发票、报告、证书 | Browser Run /pdf | 可短请求触发,结果仍建议存 R2 |
| 上传后摘要、索引、提取 | R2 event notification + Queue + Worker | 异步 |
| 合并、拆分、OCR、复杂原生库、大文件 | 评估 Container 或外部处理器 | 异步、带资源限制 |
Browser Run 的 /pdf 接受 url 或 html。它适合把可控页面渲染为文档,不等于通用 PDF 编辑器。Cloudflare 官方的上传后摘要教程使用 R2 event notifications、Queues 和 Workers AI,说明文件处理应该与用户上传请求解耦。
任务状态模型
D1 保存 job ID、tenant、input key、operation、status、attempt、output key 与错误类别;R2 保存输入和输出对象;Queue 传递最小消息。消息只包含稳定 ID 和受控 object key,不包含完整文件或 Secret。
await env.PDF_JOBS.send({
jobId,
tenantId,
inputKey,
operation: 'extract-text',
});
return Response.json(
{ jobId, status: 'queued' },
{ status: 202 },
);消费者从可信 job 记录重新加载参数,并使用唯一 output key。若同一消息重复投递,消费者检查 job/version,已完成任务直接确认,不覆盖不同版本结果。
完成处理流程
创建上传合同
认证用户,限制声明大小、允许 application/pdf,生成租户范围内 object key 和 job ID。不要让浏览器决定 bucket 或任意目标路径。
上传后再验证
对象到达 R2 后读取 metadata,检查真实大小、类型、所有权和 job 对应关系。加密、损坏或超出本流程能力的 PDF 进入明确失败状态。
分派到正确处理器
HTML 生成走 Browser Run;文本提取/摘要按当前 Worker 与模型限制评估;依赖原生二进制、耗时长或内存大的工作进入 Container/外部处理器。不要靠分块掩盖一个不适合 Worker 的运行时需求。
保存可恢复结果
先把输出写入版本化 R2 key,再以条件更新将 job 标记 done。若数据库更新失败,重试会发现同一输出;孤儿输出由延迟清理任务处理。
提供状态与下载
状态接口只返回当前用户/租户的任务。下载路由重新授权,设置正确内容类型、文件名与缓存策略,不暴露内部 bucket key。
安全与成本
输入
隔离
滥用
隐私
如果加入摘要或分类,它只是任务处理器中的可选 AI 步骤。PDF 生成、存储、权限与下载在关闭 AI 时仍应工作。
验证矩阵
测试有效小文件、空文件、错误 MIME、超限、加密/损坏、重复消息、处理器超时、R2 写失败、D1 更新失败、跨租户 job ID 和已删除输出。至少一次证明重复消费不会生成两份业务结果。
验证与排障
| 现象 | 先检查 | 恢复动作 |
|---|---|---|
创建任务返回 invalid_or_unsafe_html | 是否包含脚本、iframe、外部 URL 或超过大小 | 使用自包含、无活动内容的受控 HTML 模板 |
返回 queue_unavailable | producer binding 与 Queue 是否存在 | 保留失败 job 记录,恢复 Queue 后显式重建任务 |
job 长时间 running | consumer、重试次数与 Browser Run 使用量 | 查看 Queue/Browser 指标,避免盲目重复提交 |
最终 processor_failed | Browser Run 响应、输入对象与配额 | 修复后创建新 version;不要覆盖旧输出 key |
远程边界与回滚
Browser Run binding、R2 event notification、Queue consumer、Container 和远程 bucket 都会修改外部状态,本教程不自动创建。代码回滚不能撤回已在队列中的旧消息;消费者要接受版本字段并在不支持时转入 dead-letter/失败状态。删除功能先撤销下载权限和标记过期,再延迟物理删除输入与输出。
下一步:执行生产发布清单。
官方来源
这篇内容帮你完成目标了吗?
内测反馈只在当前浏览器生成,不会自动上传。