快速上手 — 首次边缘渲染
本页会带你把一段 HTML 字符串转换成一个 PDF 文件。这里展示的每个调用都对应一个方法,且每个方法的行为都已在 tests/Unit/Cloudflare/CloudflareHtmlRendererTest.php 中验证。
先决条件
标题为“先决条件”的章节- 一个通过 HTTPS 提供渲染合约的 Worker 端点。
- 一个 Worker 可接受的 bearer token。
- 运行路径中需要有一个 PSR-18 客户端和 PSR-17 工厂(请参阅 /integrations/cloudflare/install/)。
根据 CloudflareResponseParser 观察到的 Worker 合约:成功时返回 HTTP 200。响应会携带 Content-Type: application/pdf(原始 PDF 字节)或 Content-Type: application/json(包含一个 base64 编码的 pdf 字段)。任何非 200 的状态,或正文开头并非 %PDF 标记,都会被视为失败。
步骤 1 — 构建配置
标题为“步骤 1 — 构建配置”的章节<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Cloudflare\CloudflareRendererConfig;
$config = new CloudflareRendererConfig( workerUrl: 'https://pdf-renderer.example.workers.dev/render', apiToken: getenv('CF_PDF_TOKEN') ?: throw new RuntimeException('CF_PDF_TOKEN not set'),);token 从环境中读取,绝不能写死在代码中。workerUrl 必须使用 HTTPS。如果你传入 http:// URL,桥接层会在发送任何请求之前以 Worker URL must use HTTPS 拒绝该配置。
步骤 2 — 构建渲染器
标题为“步骤 2 — 构建渲染器”的章节use GuzzleHttp\Client;use GuzzleHttp\Psr7\HttpFactory;use NextPDF\Cloudflare\CloudflareHtmlRenderer;
$httpFactory = new HttpFactory();
$renderer = new CloudflareHtmlRenderer( config: $config, httpClient: new Client(), // PSR-18 ClientInterface requestFactory: $httpFactory, // PSR-17 RequestFactoryInterface streamFactory: $httpFactory, // PSR-17 StreamFactoryInterface logger: null, // optional PSR-3 LoggerInterface responseFactory: $httpFactory, // PSR-17; enables the pinned transport);构造函数需要四个必选参数:配置、PSR-18 客户端、request 工厂和 stream 工厂。另外四个参数可选:logger、本地渲染器工厂、明确的 HTML 安全策略,以及 response 工厂。提供 response 工厂后,如果存在已解析的 IP 集合或 SPKI pin 集合,就会启用固定(pinned)的 cURL 传输(请参阅 /integrations/cloudflare/security-and-operations/)。
步骤 3 — 渲染并写出
标题为“步骤 3 — 渲染并写出”的章节use NextPDF\Cloudflare\Exception\CloudflareNotAvailableException;use NextPDF\Cloudflare\Exception\CloudflareRenderException;
try { $result = $renderer->render('<h1>Hello from the edge</h1>');
if (!$result->isValid()) { throw new RuntimeException('Worker did not return a valid PDF'); }
file_put_contents('output.pdf', $result->pdfData); printf("Wrote %d bytes from edge %s in %.1f ms\n", $result->size(), $result->renderLocation !== '' ? $result->renderLocation : 'unknown', $result->renderTimeMs, );} catch (CloudflareRenderException $e) { // Worker answered but the render failed (HTTP error or malformed body). fwrite(STDERR, 'Render failed: ' . $e->getMessage() . PHP_EOL); exit(1);} catch (CloudflareNotAvailableException $e) { // Worker unreachable and no usable fallback. fwrite(STDERR, 'Edge unavailable: ' . $e->getMessage() . PHP_EOL); exit(2);}render() 默认使用 A4 宽度(595.28 PDF 点)并自动检测高度(heightPt: 0)。这两种异常类型有意区分开。CloudflareRenderException 表示 Worker 端失败,并且不会通过备援机制重试。CloudflareNotAvailableException 表示无法连接到边缘,且没有可用的本地备援。
步骤 4 — 查看结果
标题为“步骤 4 — 查看结果”的章节CloudflareRenderResult 是 final readonly。以下字段在二进制路径中由响应标头填充,在 JSON 路径中则由 JSON 字段填充。
| 成员 | 来源 |
|---|---|
pdfData | 原始 PDF 字节 |
widthPt | 你所请求的宽度 |
heightPt | X-Pdf-Height-Pt 标头 / JSON heightPt;当缺漏或非正值时,默认为 841.89(A4 高度) |
contentHeightPx | X-Content-Height-Px / JSON contentHeightPx |
renderLocation | 由 CF-Ray 标头后缀(二进制路径)或 JSON renderLocation 派生而来 |
renderTimeMs | X-Render-Time-Ms / JSON renderTimeMs |
size() | strlen($pdfData) |
isValid() | 当字节以 %PDF 开头时为 true |
可选 — 自定义纸张尺寸、字体、CSS
标题为“可选 — 自定义纸张尺寸、字体、CSS”的章节$result = $renderer->render( html: '<div style="font-family: NotoSansCJK;">繁體中文文件</div>', widthPt: 595.28, heightPt: 841.89, // explicit A4; 0 lets the Worker auto-detect fontFiles: ['NotoSansCJKtc-Regular.ttf'],);fontFiles 仅在配置中设置了 r2FontBucket 时才有意义。这样,负载会携带 bucket 名称和请求的字体文件路径,供 Worker 加载。
可选 — 连接性探测
标题为“可选 — 连接性探测”的章节if ($renderer->isAvailable()) { $result = $renderer->render($html);}isAvailable() 会向 Worker URL 发送经过验证的 HTTP HEAD 请求。只要状态低于 500,它就会返回 true。配置无效或请求失败时,它会返回 false,不会抛出异常。请把它视为提示,而不是保证。Worker 后续的 POST 仍可能失败。
另请参阅
标题为“另请参阅”的章节- /integrations/cloudflare/production-usage/ — 备援接入、遥测、R2 归档。
- /integrations/cloudflare/troubleshooting/ — 每类失败对应的异常与消息。
- /integrations/cloudflare/configuration/ — 完整的字段参考。