跳轉到

Edge 渲染

EdgeRenderernextpdf/cloudflare 的核心元件,負責在 Cloudflare Workers 的無狀態、無檔案系統、CPU 時間受限的環境中執行 NextPDF Core 生成 PDF。

PHP Compatibility

This example uses PHP 8.5 syntax. If your environment runs PHP 8.1 or 7.4, use NextPDF Backport for a backward-compatible build.

渲染模式

EdgeRenderer 支援兩種渲染模式,根據文件複雜度與 CPU 時間預算自動切換:

模式 說明 適用場景
Full Mode 完整 NextPDF Core 功能 複雜度低到中的文件
Lightweight Fallback 預先渲染的模板 + 動態資料填充 CPU 超時或複雜文件

建立 EdgeRenderer

<?php

declare(strict_types=1);

use NextPDF\Cloudflare\EdgeRenderer;
use NextPDF\Cloudflare\Config\EdgeRendererConfig;
use NextPDF\Cloudflare\Fallback\LightweightTemplateFallback;

$renderer = EdgeRenderer::create(
    config: EdgeRendererConfig::create(
        maxCpuMs: 20000,              // 目標 CPU 時間(ms),超出則觸發 fallback
        maxMemoryMb: 100,             // 記憶體上限感知(MB)
        fallbackOnTimeout: true,      // CPU 超時時自動降級
        fallbackOnMemoryPressure: true,
        fallback: LightweightTemplateFallback::fromFile(
            templatePath: __DIR__ . '/templates/fallback.pdf',
        ),
    ),
);

渲染 PDF

基本渲染

use NextPDF\Core\Document;

$pdfBytes = $renderer->render(function (Document $doc): void {
    $doc->addPage();
    $doc->text('Cloudflare Edge PDF', x: 20, y: 30, fontSize: 18);
    $doc->text('Generated at: ' . date('Y-m-d H:i:s'), x: 20, y: 50);
});

在 Worker Handler 中使用

<?php

declare(strict_types=1);

use NextPDF\Cloudflare\EdgeRenderer;
use NextPDF\Cloudflare\Http\WorkerResponse;

// Cloudflare Workers PHP Runtime 的請求處理器
function handle(array $request): array
{
    $renderer = EdgeRenderer::create(EdgeRendererConfig::default());

    $pdfBytes = $renderer->render(function (\NextPDF\Core\Document $doc): void {
        $doc->addPage()->text('Hello from Edge', x: 20, y: 30);
    });

    return WorkerResponse::pdf(
        bytes: $pdfBytes,
        filename: 'edge-document.pdf',
        disposition: 'attachment',
    );
}

Fallback 策略

當 PDF 生成超出 CPU 預算或記憶體壓力過高時,EdgeRenderer 自動觸發 fallback:

use NextPDF\Cloudflare\Fallback\FallbackStrategyInterface;
use NextPDF\Cloudflare\Fallback\LightweightTemplateFallback;
use NextPDF\Cloudflare\Fallback\StaticPdfFallback;
use NextPDF\Cloudflare\Fallback\RedirectFallback;

// 策略 1:以輕量模板填充資料(推薦)
$fallback = LightweightTemplateFallback::fromBytes($templatePdfBytes)
    ->withDataInjector(function (\NextPDF\Artisan\PageImport\FormFiller $filler, array $data): void {
        $filler->fill('customer_name', $data['name']);
        $filler->fill('invoice_total', number_format($data['total'], 2));
    });

// 策略 2:回傳靜態預先生成的 PDF
$fallback = StaticPdfFallback::fromR2Key('fallback/generic-invoice.pdf');

// 策略 3:重定向至伺服器端生成端點
$fallback = RedirectFallback::to('https://api.example.com/pdf/generate');

CPU 時間監控

use NextPDF\Cloudflare\Monitoring\CpuTimer;

$timer = CpuTimer::start();

$pdfBytes = $renderer->render(function (\NextPDF\Core\Document $doc) use ($timer): void {
    foreach ($this->pages as $index => $pageData) {
        $doc->addPage();
        $doc->text($pageData['content'], x: 20, y: 30);

        // 提前檢查是否接近 CPU 上限
        if ($timer->elapsedMs() > 15000) {
            throw new \NextPDF\Cloudflare\Exception\CpuBudgetExceededException(
                "Stopping at page {$index} to avoid CPU timeout",
            );
        }
    }
});

$cpuUsed = $timer->stop(); // CpuTimerResult

WorkerResponse 輔助類別

use NextPDF\Cloudflare\Http\WorkerResponse;

// PDF 下載回應(含 OWASP 標頭)
return WorkerResponse::pdf(
    bytes: $pdfBytes,
    filename: 'document.pdf',
    disposition: 'attachment', // 或 'inline'
);

// 包含自訂標頭
return WorkerResponse::pdf(
    bytes: $pdfBytes,
    filename: 'document.pdf',
    additionalHeaders: [
        'X-Generation-Time-Ms' => (string) $cpuUsed->totalMs(),
        'CF-Cache-Status'      => 'MISS',
    ],
);

例外處理

例外類別 觸發條件
CpuBudgetExceededException CPU 時間超出設定上限
MemoryPressureException 記憶體使用量超出設定上限
FallbackFailedException Fallback 策略本身也失敗
EdgeRenderException 一般性渲染失敗

參見