跳转到内容

Cloudflare API 参考

这个 NextPDF\Cloudflare 包是一层边缘渲染桥接:你的 PHP 程序持有 HTML,Cloudflare Worker 持有无头浏览器。这个包提供以 Worker 为后端的 HTML renderer(CloudflareHtmlRenderer)及其返回的值对象、用于保护渲染 endpoint 的请求防护层(ApiProtection)、用于存储已渲染 PDF 的 R2 归档服务(R2ArchiveManager),以及用于 TLS/DNS 加固的固定传输辅助工具。配置存放在三个不可变对象中(CloudflareRendererConfigApiProtectionConfigR2ArchiveConfig)。

从这里开始:如果你刚接触这个包,先创建一个 CloudflareRendererConfig,把它接入 CloudflareHtmlRenderer,再调用 render()。这次调用会把你的 HTML 发送到 Worker,并返回一个带有 PDF 字节的 CloudflareRenderResult。其余所有功能(防护、归档、固定)都围绕这次调用叠加。

以下代码片段展示了这个包最常见的实际工作流程。每一段都可以独立运行,已对照 src/Cloudflare/ 源代码验证,并从环境变量读取密钥。

在边缘把一段 HTML 字符串渲染成 PDF,这是唯一的标准渲染调用:

<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use NextPDF\Cloudflare\CloudflareHtmlRenderer;
use NextPDF\Cloudflare\CloudflareRendererConfig;
$httpFactory = new HttpFactory();
$renderer = new CloudflareHtmlRenderer(
config: new CloudflareRendererConfig(
workerUrl: 'https://pdf-renderer.example.workers.dev/render',
apiToken: getenv('CF_PDF_TOKEN') ?: throw new RuntimeException('CF_PDF_TOKEN not set'),
),
httpClient: new Client(),
requestFactory: $httpFactory,
streamFactory: $httpFactory,
responseFactory: $httpFactory,
);
$result = $renderer->render('<h1>Hello from the edge</h1>', widthPt: 595.28);
if ($result->isValid()) {
file_put_contents('output.pdf', $result->pdfData);
}

作用:通过 HTTPS 把 HTML 发送到 Worker,并在 isValid() 确认为真正的 PDF 后,把返回的 A4 PDF 字节写入磁盘。

把已渲染的 PDF 归档到 R2,并返回一个短期链接:

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\R2ArchiveConfig;
use NextPDF\Cloudflare\R2ArchiveManager;
$archive = new R2ArchiveManager(
config: R2ArchiveConfig::fromArray([
'bucket_name' => 'pdf-archive',
'account_id' => getenv('CF_ACCOUNT_ID') ?: '',
'access_key_id' => getenv('R2_ACCESS_KEY_ID') ?: '',
'secret_access_key' => getenv('R2_SECRET_ACCESS_KEY') ?: '',
]),
httpClient: $httpClient, // PSR-18 ClientInterface
requestFactory: $requestFactory, // PSR-17 RequestFactoryInterface
streamFactory: $streamFactory, // PSR-17 StreamFactoryInterface
);
$upload = $archive->upload($result->pdfData, 'invoice-1234.pdf');
$signedUrl = $upload->isValid()
? $archive->generateSignedUrl($upload->key, expiresInSeconds: 600)
: null;

作用:把 PDF 字节上传到按日期分区的 R2 键,成功后生成一个 10 分钟有效的预签名 URL,供临时下载。

在执行昂贵的 Worker 任务之前,先保护渲染 endpoint:

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\ApiKeyValidator;
use NextPDF\Cloudflare\ApiProtection;
use NextPDF\Cloudflare\ApiProtectionConfig;
$protection = new ApiProtection(
config: new ApiProtectionConfig(maxRequestsPerMinute: 30),
keyValidator: new ApiKeyValidator([getenv('RENDER_API_KEY') ?: '']),
);
$decision = $protection->checkRequest(
clientId: $clientIp,
payloadSize: strlen($html),
apiKey: $presentedApiKey,
);
if (!$decision->allowed) {
// Reject with 429 and rate-limit headers before any render call.
return [429, $decision->toHeaders(), $decision->denialReason];
}

作用:依次验证 API 密钥、载荷大小,再验证每个客户端的速率限制,返回单一决策以及请求被拒时要附带的响应头。

renderer 表格是核心接口。当你要构建配置、创建 renderer,或发起渲染与可用性调用时,就使用这张表。

符号参数默认行为返回抛出或失败条件备注
new CloudflareRendererConfig(string $workerUrl, string $apiToken, int $renderTimeout = 30, string $defaultCss = '', int $maxHtmlSize = 5000000, ?string $r2FontBucket = null, bool $fallbackToLocal = true, array $pinnedPublicKeys = [], array $backupPublicKeys = [])Worker URL、bearer token、超时、CSS、大小上限、可选的 R2 字体 bucket、fallback 标志、pin 集合。默认启用本地 fallback;当 pin 数组为空时停用固定。CloudflareRendererConfig预期无。妥善保管 API token;优先使用 HTTPS 的 worker URL。
CloudflareRendererConfig::fromArray(array $config)worker_urlapi_tokenrender_timeoutdefault_cssmax_html_sizer2_font_bucketfallback_to_local、pin 数组。未提供的可选键会采用构造函数默认值。CloudflareRendererConfig预期无。对应 Framework(框架)风格的配置数组。
CloudflareRendererConfig::isValid()无。需要非空的 worker URL 与 API token。bool预期无。无效配置会让 renderer 触发 fallback 或失败。
CloudflareRendererConfig::allPublicKeyPins()无。合并主公钥 pin 与备用公钥 pin。list<string>预期无。空列表会停用固定。
new CloudflareHtmlRenderer(CloudflareRendererConfig $config, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, ?LoggerInterface $logger = null, ?LocalRendererFactoryInterface $localRendererFactory = null, ?HtmlSecurityPolicyInterface $htmlSecurityPolicy = null, ?ResponseFactoryInterface $responseFactory = null)配置、PSR HTTP 依赖项、可选的 logger、可选的本地 fallback 工厂、可选的 HTML 策略、可选的 response 工厂。未提供 HTML 策略时,使用 DefaultHtmlSecurityPolicyCloudflareHtmlRenderercontainer(容器)装配错误。需要时,response 工厂会启用固定 cURL 传输。
CloudflareHtmlRenderer::render(string $html, float $widthPt = 595.28, float $heightPt = 0, array $fontFiles = [])HTML、页面宽度、页面高度、R2 中的字体文件。A4 宽度;自动高度;无字体文件。CloudflareRenderResultCloudflareNotAvailableExceptionCloudflareRenderException、验证失败。在网络 I/O 之前先验证 HTML 大小与 worker URL。
CloudflareHtmlRenderer::getHtmlSecurityPolicy()无。返回已配置的解析层策略。HtmlSecurityPolicyInterface预期无。与 endpoint 防护及 Worker URL 验证搭配使用。
CloudflareHtmlRenderer::isAvailable()无。当配置有效时,向 worker 发出 HEAD 请求。bool发生错误时返回 false用于就绪检查,不要当作唯一的运行时防线。

当你需要 request/result 值对象(CloudflareRenderResultCloudflareRenderPayload),或需要在任何网络 I/O 之前验证 HTML、Worker URL 与 DNS pin 的静态传输层检查时,就使用这张表。

符号参数默认行为返回抛出或失败条件备注
new CloudflareRenderResult(string $pdfData, float $widthPt, float $heightPt, float $contentHeightPx = 0.0, string $renderLocation = '', float $renderTimeMs = 0.0)PDF 字节、宽度、高度、测得的内容高度、边缘位置、渲染时间。当 Worker 未返回时,元数据为空。CloudflareRenderResult预期无。通常由 CloudflareResponseParser::parse() 返回。
CloudflareRenderResult::isValid()无。检查 PDF 字节非空且以 PDF 头开头。bool预期无。在归档或把字节传给其他层之前使用。
CloudflareRenderResult::size()无。计算已渲染 PDF 的字节数。int预期无。把这个值送入配额与审计逻辑。
new CloudflareRenderPayload(string $html, float $widthPt, float $heightPt = 0, string $defaultCss = '', ?string $r2FontBucket = null, array $fontFiles = [])HTML、尺寸、CSS、可选的 R2 字体 bucket、字体文件列表。自动高度、无默认 CSS、无 R2 字体 bucket、无字体文件。CloudflareRenderPayload预期无。请求载荷值对象。
CloudflareRenderPayload::toJson()无。把 HTML、尺寸、CSS 与字体引用序列化给 Worker。stringJSON 编码错误。底层的请求载荷 API。
CloudflareResponseParser::parse(ResponseInterface $response, float $requestedWidthPt)Worker 响应与请求宽度。接受二进制 PDF 响应与结构化 JSON 响应。CloudflareRenderResultCloudflareRenderException:当 Worker 输出失败或无效时抛出。renderer 使用的中央 parser(解析器)。
CloudflareSecurityPolicy::validate(string $html, int $maxSize)HTML 输入与大小上限。应用这个包的 HTML 输入策略。void验证异常。在 Worker 边界外检查不受信任的输入。
CloudflareSecurityPolicy::validateWorkerUrl(string $url)Worker URL(网址)。解析并验证目标地址。array验证异常。在网络 I/O 之前阻止不安全的 endpoint 形式。
CloudflareSecurityPolicy::assertPinsStillValid(string $host, array $pinnedIps)主机与固定的 IP 列表。验证 DNS pin 的预期值。void当 pin 过期或无效时抛出验证异常。在启用固定的部署运维检查期间使用。

当你要保护渲染 endpoint 时使用这张表:API 密钥验证、载荷大小与速率限制检查,以及它们产生的 result/header 对象。

符号参数默认行为返回抛出或失败条件备注
new ApiProtection(ApiProtectionConfig $config, ?ApiKeyValidator $keyValidator = null, ?Closure $clock = null)防护配置、可选的密钥验证器、可选的时钟。未提供时钟时使用系统时间。ApiProtection预期无。在测试中注入确定性时钟。
ApiProtection::checkRequest(string $clientId, int $payloadSize, string $apiKey = '')客户端标识符、载荷大小、可选的 API 密钥。只有当配置不要求密钥时,才允许空的 API 密钥。ApiProtectionResult预期无。依次检查 API 密钥、大小,再检查速率限制。
ApiProtection::getRateLimit(string $clientId)客户端标识符。不会记录一次请求。RateLimitResult预期无。用来添加速率限制响应头。
new ApiKeyValidator(array $validKeys = [])明文有效密钥列表。空列表会拒绝所有密钥。ApiKeyValidator预期无。把密钥存放在代码之外,通过配置加载。
ApiKeyValidator::validate(string $key)原始密钥。与配置好的明文密钥做时序安全比较。bool预期无。敏感参数;不要记录原始密钥。
ApiKeyValidator::addKey(string $key)原始密钥。把哈希后的密钥加入一个新的验证器实例。self预期无。把返回的实例当作更新后的验证器。
ApiKeyValidator::revokeKey(string $key)原始密钥。从一个新的验证器实例移除匹配的哈希。self预期无。把返回的实例当作更新后的验证器。
ApiKeyValidator::hashKey(string $key)原始密钥。生成用于存储的哈希表示。string预期无。不要在日志或客户端响应中暴露哈希。
ApiKeyValidator::validateHashed(string $key, array $hashedKeys)原始密钥与候选哈希。与提供的哈希做常量时间比较。bool预期无。供自定义密钥存储使用的底层辅助方法。
new ApiProtectionConfig(int $maxRequestsPerMinute = 60, int $maxRequestsPerHour = 1000, int $maxPayloadSizeBytes = 10485760, array $allowedOrigins = [], bool $requireApiKey = true, string $apiKeyHeader = 'X-Api-Key', int $rateLimitWindowSeconds = 60)请求上限、载荷上限、允许的来源、API 密钥要求、请求头名称、窗口长度。60/minute、1000/hour、10 MiB 载荷、需要 API 密钥。ApiProtectionConfig预期无。在测试中直接构建,或以 fromArray() 加载。
ApiProtectionConfig::fromArray(array $data)max_requests_per_minutemax_requests_per_hourmax_payload_size_bytesallowed_originsrequire_api_keyapi_key_headerrate_limit_window_seconds未提供的键会采用构造函数默认值。ApiProtectionConfig预期无。用于框架配置加载。
ApiProtectionConfig::isValid()无。需要正值上限与一致的 size/window 值。bool预期无。在对外开放 endpoint 之前先验证。
new ApiProtectionResult(bool $allowed, string $denialReason = '', ?RateLimitResult $rateLimit = null)决策、拒绝原因、可选的速率限制结果。空的拒绝原因,且无速率限制结果。ApiProtectionResult预期无。ApiProtection::checkRequest() 返回。
ApiProtectionResult::toHeaders()无。当有速率数据时,输出速率限制响应头。array<string, string>预期无。附加到 worker 或框架响应上。
new RateLimitResult(bool $allowed, int $remainingRequests, int $retryAfterSeconds, string $clientId)决策、剩余次数、重试延迟、客户端 ID。无默认值。RateLimitResult预期无。单次检查的不可变结果。
RateLimitResult::toHeaders()无。输出剩余限制与重置响应头。array<string, string>预期无。用于可观测性与客户端退避。
new RateLimitEntry(string $clientId, int $requestCount = 0, int $windowStart = 0, int $hourlyCount = 0, int $hourlyWindowStart = 0)客户端 ID 与可变计数器。计数器从零开始。RateLimitEntry预期无。内存中的跟踪对象。
RateLimitEntry::increment()无。为单个 client/window 递增内存计数器。void预期无。ApiProtection 使用的底层辅助方法。
RateLimitEntry::isExpired(int $windowSeconds)以秒为单位的窗口长度。与当前时间比较。bool预期无。运行时的过期辅助方法。
RateLimitEntry::isExpiredAt(int $now, int $windowSeconds)时钟值与窗口长度。与提供的时钟值比较。bool预期无。确定性测试辅助方法。
RateLimitEntry::reset()无。重置计数与窗口起始时间。void预期无。在新窗口开始时使用。

当你要把已渲染的 PDF 存储到 Cloudflare R2 时使用这张表:归档服务、它的配置与对象键类型,以及你在对外开放 URL 之前要检查的上传结果。

符号参数默认行为返回抛出或失败条件备注
new R2ArchiveManager(R2ArchiveConfig $config, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory)R2 配置与 PSR HTTP factories/client.构建期间不会发出网络调用。R2ArchiveManager容器装配错误。主要的归档服务。
R2ArchiveManager::upload(string $pdfData, string $filename, array $metadata = [])原始 PDF 字节、原始文件名、字符串元数据。空的元数据;按日期分区的键。R2UploadResult当配置、大小、HTTP 或传输失败时,返回不成功的结果。一般上传失败时不会抛出异常。
R2ArchiveManager::generateSignedUrl(string $key, int $expiresInSeconds = 3600)对象键与 URL TTL。一小时有效的签名 URL。string无效配置造成的签名错误。对敏感 PDF 保持较短的 TTL。
R2ArchiveManager::buildObjectKey(string $filename)原始文件名。使用配置好的路径前缀与当前日期。R2ObjectKey预期无。用于可预测的归档分区。
R2ArchiveManager::createPutRequest(R2ObjectKey $key, string $data, array $metadata = [])对象键、原始字节、元数据。签名一个 PUT 请求。RequestInterface请求构建错误。供自定义传输使用的底层 API。
new R2ArchiveConfig(string $bucketName, string $accountId, string $accessKeyId, string $secretAccessKey, string $endpoint = '', string $pathPrefix = 'pdfs/', int $maxFileSizeBytes = 104857600)bucket、账户 ID、凭证、endpoint 覆盖值、键前缀、对象大小上限。推导出的 endpoint、pdfs/ 前缀、100 MiB 对象大小上限。R2ArchiveConfigInvalidArgumentException:当 bucket 名称无效时抛出。把凭证视为带有密钥的配置。
R2ArchiveConfig::fromArray(array $data)账户 ID、bucket、凭证、路径前缀、endpoint 覆盖值、大小上限。未提供的值会采用构造函数默认值。R2ArchiveConfig提供时,bucket 名称无效。用于应用程序配置加载。
R2ArchiveConfig::isValid()无。需要非空的账户、bucket、访问密钥与密钥。bool预期无。无效配置会让上传以结构化结果失败。
R2ArchiveConfig::getEndpoint()无。使用明确的 endpoint,或从账户 ID 推导出 Cloudflare R2 endpoint。string预期无。用于构建签名请求。
new R2ObjectKey(string $key, string $bucket)完整的对象键与 bucket。不做规范化。R2ObjectKey预期无。通常由 R2ObjectKey::generate() 创建。
R2ObjectKey::generate(string $prefix, string $filename, ?DateTimeInterface $date = null)前缀、原始文件名、可选的日期。按日期分区并清理过的对象键。R2ObjectKey预期无。在测试中注入日期,以取得确定性的键。
R2ObjectKey::fullPath()无。拼接分区路径与对象文件名。string预期无。把这个值存储为对象键。
new R2UploadResult(bool $success, string $key, string $etag = '', int $size = 0, string $error = '')成功标志、对象键、ETag、字节大小、错误消息。空的 ETag、零大小、空的错误。R2UploadResult预期无。R2ArchiveManager::upload() 返回。
R2UploadResult::isValid()无。当上传成功且键与 ETag 都存在时,视为有效。bool预期无。在对外开放 URL 之前先检查。
R2UploadResult::publicUrl(string $customDomain = '')可选的自定义公开域名。未提供自定义域名时,返回裸对象键。string预期无。除非策略允许,否则避免对敏感文件使用公开 URL。

这张表只用于底层装配:cURL 层面的 IP/SPKI 固定,以及当 Worker 无法连接时作为 fallback 路径的本地 renderer 契约。

符号参数默认行为返回抛出或失败条件备注
new PinnedCurlTransport(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory, array $pinnedIps = [], array $pinnedPublicKeys = [], int $timeoutSeconds = 30)PSR-17 工厂、固定的 IP、固定的公钥、超时。无 pin,且超时 30 秒。PinnedCurlTransport预期无。只在需要 cURL 层面固定时使用。
PinnedCurlTransport::sendRequest(RequestInterface $request)PSR-7 请求。以配置好的超时与固定控制通过 cURL 发送。ResponseInterfacePSR-18 传输异常。只在框架的 HTTP 客户端无法强制执行相同固定策略时使用。
PinnedCurlTransport::buildCurlOptions(RequestInterface $request, string $host, int $port)请求、目标主机、目标端口。构建 sendRequest() 所用的 cURL 选项数组。array无效的请求或 pin 配置错误。底层的测试与诊断钩子。
LocalRendererInterface::render(string $html, array $options = [])HTML 与 renderer 选项。仅为契约;由实现决定默认值。string实现各自定义的渲染错误。当 Worker 渲染无法使用时,作为本地 fallback 使用。
LocalRendererFactoryInterface::create()无。创建一个本地 renderer 实现。LocalRendererInterface工厂或依赖项错误。把 fallback renderer 的构建工作移出 CloudflareHtmlRenderer
  • 把 Worker URL 视为一个网络边界。在渲染之前,先验证目标地址、大小与身份验证。
  • 把 API 防护结果当作策略输出,而不是异常控制流。
  • R2 上传会返回结构化的成功或错误结果;两条路径都要处理。