Cloudflare 开发者指南
Cloudflare 套件会将渲染工作移到 Worker 边界。请将 Worker 渲染、本地回退、API 防护与 R2 归档视为彼此独立的能力,并分别处理各自的失败场景。
当你要围绕 nextpdf/cloudflare 构建边缘渲染服务、受防护的渲染端点、归档流程或本地回退路径时,请使用本指南。
架构边界
标题为“架构边界”的章节| 层 | 负责方 | 职责 | 不要放在这里 |
|---|---|---|---|
| 应用端点 | 应用 | 验证调用方、规范化渲染请求,并落实业务策略。 | 把 Worker token 硬编码在源代码中。 |
| API 防护 | nextpdf/cloudflare 与应用 | API key、payload 大小与进程内速率限制的判定。 | 计费、租户权益,或持久化的配额强制执行。 |
| Cloudflare renderer(渲染器) | nextpdf/cloudflare | 验证 HTML 与 Worker URL、发送渲染 payload,并解析响应。 | 模板渲染或域名查询。 |
| Worker(运算单元) | 应用部署 | 执行 Browser Rendering,并返回 PDF 字节或结构化结果。 | PHP 端的存储策略。 |
| 本地回退 | 应用部署 | 当 Worker 不可用时执行渲染。 | 会掩盖运维中断的静默回退。 |
| R2 归档 | nextpdf/cloudflare | 上传 PDF、创建对象键,并生成签名 URL。 | 未经审查的敏感业务元数据。 |
运行时生命周期
标题为“运行时生命周期”的章节| 阶段 | 行为 | 开发者动作 |
|---|---|---|
| 配置创建 | 加载 Worker URL、API token、超时、大小限制、回退与 pin。 | 将秘密信息放在部署配置中。 |
| 请求防护 | 选用的 ApiProtection 会验证 key、大小与速率限制。 | 在成本较高的渲染工作之前执行。 |
| 调用 renderer | CloudflareHtmlRenderer 会验证 HTML 与 Worker URL,然后发送 JSON。 | 分别处理 Worker 不可用与渲染失败的情况。 |
| 解析响应 | CloudflareResponseParser::parse() 接受二进制 PDF 或结构化 JSON 输出。 | 拒绝无效或非 PDF 输出。 |
| 本地回退 | 选用的本地 renderer 会处理 Worker 失败。 | 仅在主机支持时注入本地 renderer 工厂。 |
| R2 归档 | R2ArchiveManager 会存储 PDF 字节并生成签名 URL。 | 除非有意存储,否则保持元数据不含敏感信息。 |
建议的应用结构
标题为“建议的应用结构”的章节| 路径 | 用途 |
|---|---|
app/Pdf/Cloudflare/* | 位于 CloudflareHtmlRenderer 外层的应用包装层。 |
app/Pdf/Workers/* | Worker 请求 DTO 与端点专属策略。 |
app/Pdf/Archive/* | R2 归档编排与保留决策。 |
app/Pdf/Fallback/* | LocalRendererFactoryInterface 实现(允许回退时)。 |
tests/Pdf/Cloudflare/* | Worker 中断、无效 token、payload 与归档等测试。 |
请将 PHP API token 与 Worker token 分开保管。PHP 端会向 Worker 进行身份验证。Worker 在执行浏览器任务之前,应先验证传入请求。
<?php
use NextPDF\Cloudflare\ApiProtection;use NextPDF\Cloudflare\ApiProtectionConfig;use NextPDF\Cloudflare\ApiKeyValidator;
$protection = new ApiProtection( new ApiProtectionConfig(maxRequestsPerMinute: 30), new ApiKeyValidator([$expectedApiKey]),);
$result = $protection->checkRequest( clientId: $clientId, payloadSize: strlen($html), apiKey: $presentedApiKey,);
if (!$result->allowed) { return new JsonResponse(['error' => $result->denialReason], 429, $result->toHeaders());}renderer 模式
标题为“renderer 模式”的章节使用 Framework(框架)提供的 PSR-18 与 PSR-17 依赖项构建 renderer。请让本地回退保持显式,这样运维人员才能看出系统何时不再使用 Worker。
<?php
use NextPDF\Cloudflare\CloudflareHtmlRenderer;use NextPDF\Cloudflare\CloudflareRendererConfig;
$renderer = new CloudflareHtmlRenderer( config: CloudflareRendererConfig::fromArray([ 'worker_url' => getenv('NEXTPDF_CLOUDFLARE_WORKER_URL'), 'api_token' => getenv('NEXTPDF_CLOUDFLARE_API_TOKEN'), 'render_timeout' => 30, 'max_html_size' => 1_000_000, 'fallback_to_local' => false, ]), httpClient: $httpClient, requestFactory: $requestFactory, streamFactory: $streamFactory,);
$rendered = $renderer->render($html, widthPt: 595.28);R2 归档模式
标题为“R2 归档模式”的章节仅在渲染成功且策略批准后才进行归档。请将公开 URL 与签名 URL 视为彼此独立的决策。
<?php
use NextPDF\Cloudflare\R2ArchiveManager;
$upload = $archive->upload( pdfData: $rendered->pdfData, filename: 'invoice-1234.pdf', metadata: [ 'document_type' => 'invoice', ],);
if ($upload->isValid()) { $temporaryUrl = $archive->generateSignedUrl($upload->key, 600);}除非你的保留与访问策略明确允许,否则不要将客户姓名、电子邮件地址、发票总额或受监管的识别码放入对象元数据。
扩展点
标题为“扩展点”的章节| 扩展点 | 用途 | 限制 |
|---|---|---|
LocalRendererFactoryInterface | 回退到 Artisan 或其他 renderer。 | 必须返回一个实现 LocalRendererInterface 的对象。 |
ApiProtectionConfig | API key、payload 大小与速率限制策略。 | 内存中的限制以进程为单位。 |
ApiKeyValidator | 时间安全的 key 验证与 key 轮换辅助工具。 | 将秘密信息存放在源代码之外。 |
R2ArchiveConfig | bucket、凭据、路径前缀、端点与大小限制。 | 凭据绝不可写入日志。 |
PinnedCurlTransport | IP 与 SPKI pin 强制执行。 | 需要支持 cURL 的运行时与响应工厂。 |
CloudflareResponseParser | Worker 响应解析。 | 拒绝无效 PDF 或错误响应。 |
开发工作流程
标题为“开发工作流程”的章节- 先建立本地渲染路径。
- 用一份小型且具有代表性的 HTML 示例加入 Worker 渲染。
- 在对外公开端点之前,先启用请求防护。
- 仅在渲染与响应流程稳定后再加入 R2 上传。
- 测试 Worker 中断、无效 token、超量 payload、速率限制与 R2 失败等路径。
- 加入能区分 Worker 渲染、回退渲染、归档上传与签名 URL 创建的日志。
失败处理
标题为“失败处理”的章节| 失败 | 应在何处处理 | 建议的回应方式 |
|---|---|---|
| 缺少或无效的 API key | API 防护层。 | 在渲染工作开始之前就拒绝。 |
| 超量 payload | API 防护或 renderer 验证。 | 返回验证失败,且不调用 Worker。 |
| 不安全的 Worker URL | renderer 的安全策略。 | 在进行网络 I/O 之前就让配置或请求失败。 |
| Worker 不可用 | renderer 边界。 | 仅在获得允许时才使用显式回退;否则就明确失败。 |
| R2 上传失败 | 归档边界。 | 若归档为选用,则返回 PDF 响应;若策略要求必须归档,则让它失败。 |
| pin 轮换失败 | 部署与运维。 | 搭配备用 pin 与回滚计划进行轮换。 |
安全的默认值
标题为“安全的默认值”的章节| 考量项目 | 默认值 | 何时应覆写 |
|---|---|---|
| 回退 | 依配置默认值启用。 | 当本地渲染会违反部署隔离时,请禁用它。 |
| HTML 大小上限 | 5,000,000 字节。 | 对外公开端点请调低。 |
| 签名 URL 的 TTL | 3600 秒。 | 敏感 PDF 请缩短。 |
| pin 组合 | 空白。 | 仅在已有轮换计划与备用 pin 时才加入 pin。 |
| API key 需求 | 依防护配置默认值启用。 | 仅在私有、已通过验证的内部调用时才禁用。 |
测试检查清单
标题为“测试检查清单”的章节- renderer 测试涵盖有效 HTML、超量 HTML、无效 Worker URL 与 Worker 错误响应。
- API 防护测试涵盖缺少 key、无效 key、payload 过大与超过速率限制。
- R2 测试涵盖上传成功、上传过大、HTTP 状态失败、无效 bucket 与签名 URL 生成。
- 回退测试验证本地 renderer 路径是显式且可观测的。
- 传输测试涵盖带 pin 的 IP、公钥 pin、超时,以及按策略禁用的重定向。
- 可观测性测试会断言渲染、回退、归档与签名 URL 创建各有不同的日志事件。