跳到內容
getnextpdf.com

Artisan 開發者指南

Artisan 套件有兩項相互關聯的職責:透過 Chrome 繪製 HTML,並把產生的 PDF 頁面匯入 NextPDF 文件。除錯時,請分清 Chrome、parser(剖析器)與匯入器之間的邊界。

當你要撰寫 renderer 整合、長駐 worker、parser 診斷,或以 nextpdf/artisan 為核心的測試時,請參考本指南。

層級負責方職責不應放在這裡的內容
應用程式應用程式處理 HTML 產生的授權,並選擇 renderer 組態。瀏覽器行程管理。
HTML 政策應用程式與套件在繪製之前拒絕不安全或過大的 HTML。租戶授權或商業決策。
Chrome renderer(渲染器)nextpdf/artisan將 HTML 繪製成由 Chrome 產生的獨立 PDF。通用 PDF 修復或任意 PDF 編輯。
parser/匯入器nextpdf/artisan剖析已繪製的 PDF,並把其中一頁匯入為 form XObject。完整的 PDF 符合性驗證。
核心引擎nextpdf/nextpdf放置匯入的 form 物件,並寫出最終文件。Chrome CDP 生命週期。
階段行為開發者動作
建立組態ChromeRendererConfig 定義執行檔、逾時、CSS、輸入大小與沙箱行為。請使用依環境調整的組態,而不是寫死執行期推測值。
建立 rendererChromeHtmlRenderer 持有 BrowserPool。在 worker 內重複使用 renderer,並在 worker 關閉時關閉它。
驗證 HTML安全政策會檢查大小,並用預設 CSS 包裹文件。在進入此階段前先驗證呼叫端的授權。
Chrome 列印CDP 會繪製出一份獨立 PDF。除非有經過審查的政策允許,否則一律封鎖外部資源。
剖析 PDFPdfReader::parse() 會讀取 xref 資料、頁面、物件、資源與修訂版本。除非診斷本身就是目的,否則應把 parser 失敗視為繪製失敗。
匯入頁面PageImporter::import() 會擷取頁面內容、media box、資源與內嵌物件。除非工作流程刻意選擇其他頁面,否則匯入第 0 頁。
路徑用途
app/Pdf/Renderers/*包裝 ChromeHtmlRenderer 的應用程式包裝層。
app/Pdf/Templates/*HTML 範本繪製,以及將 DTO 對映到 view 的處理。
app/Pdf/Policies/*HTML 大小、資源與租戶的繪製政策。
tests/Pdf/Renderer/*使用小型 HTML 測試夾具(fixture)的 renderer 冒煙測試。
tests/Pdf/Parser/*用於匯入 Chrome 輸出的 parser 測試夾具。

請將範本繪製與瀏覽器繪製分離。renderer 應收到最終 HTML 與已知的頁面寬度。

<?php
use NextPDF\Artisan\ChromeHtmlRenderer;
use NextPDF\Artisan\ChromeRendererConfig;
use NextPDF\Artisan\PageImporter;
use NextPDF\Parser\PdfReader;
$renderer = new ChromeHtmlRenderer(new ChromeRendererConfig(
renderTimeout: 30,
maxHtmlSize: 1_000_000,
));
$result = $renderer->render($html, widthPt: 595.28);
$reader = new PdfReader($result->getPdfData());
$reader->parse();
$form = (new PageImporter())->import($reader);

為每個 worker 行程或每個 request 範圍各建立一個 renderer。重複使用 renderer 可避免反覆承擔 Chrome 啟動成本。明確關閉 renderer,可避免 worker 關閉期間發生行程洩漏。

<?php
final class InvoiceChromeRenderer
{
public function __construct(
private readonly ChromeHtmlRenderer $renderer,
) {}
public function renderInvoice(string $html): string
{
return $this->renderer
->render($html, widthPt: 595.28)
->getPdfData();
}
public function close(): void
{
$this->renderer->close();
}
}

當 Chrome 輸出無法匯入時,parser API 會派上用場。診斷應維持唯讀,並避免在成功匯入後變更 parser 狀態。

診斷問題要使用的 API預期訊號
檔案可以剖析嗎?PdfReader::parse()遇到無效的 PDF 結構時會擲回例外。
第 0 頁存在嗎?PdfReader::getPage(0)會回傳一個 PdfObject。
有內容嗎?PdfReader::getPageContentStream($page)非空的內容串流(content stream)。
有資源存在嗎?PdfReader::getPageResources($page)資源字典陣列。
有增量修訂版本嗎?PdfReader::getRevisionCount()計數大於一。
是哪個物件失敗?PdfTokenizer::getOffset() 與 parser 例外的上下文。用來縮減測試夾具的位元組偏移量。
擴充點用途限制
ChromeRendererConfig::fromArray()Framework(框架)組態對映。未知或型別錯誤的選用值會退回預設值。
HtmlSecurityPolicyInterface剖析層的 HTML 政策。不會取代傳輸、行程或授權控管。
LoggerInterface繪製與瀏覽器診斷。預設不要記錄 HTML 內容。
BrowserPool長駐 Chrome 行程的重複使用。必須在 worker 關閉時一併關閉。
PageImporter內嵌已剖析的外部頁面。reader 必須先完成剖析。
parser 類別用於診斷與匯入 Chrome 輸出。並非一般用途的 PDF 修復工具組。
  1. 在最小的繪製測試中重現該 HTML 片段。
  2. 驗證 maxHtmlSize、預設 CSS 與 Chrome 執行檔路徑。
  3. 使用固定的點(point)寬度進行繪製。
  4. 以 PdfReader::parse() 剖析回傳的 PDF 位元組。
  5. 除非工作流程刻意選擇其他頁面,否則匯入第 0 頁。
  6. 為每個能重現失敗的最小 HTML 加入測試夾具。
  7. 在 worker 關閉掛鉤中關閉 renderer。
失敗應在何處處理建議的回應方式
找不到 Chrome 執行檔部署檢查與 renderer 建構路徑。在開始接受繪製流量前,讓就緒檢查失敗。
HTML 過大HTML 政策。在啟動 Chrome 之前就予以拒絕。
瀏覽器逾時renderer 邊界。讓繪製失敗,並記錄範本名稱、大小、寬度與逾時值。
parser 失敗匯入邊界。在政策允許時,儲存一份小型且已淨化的測試夾具以供除錯。
瀏覽器行程洩漏worker 生命週期。在關閉階段將其關閉,並在受控的繪製次數後重新啟動。
考量項目預設值何時應覆寫
繪製逾時30 秒。僅針對已實測、有明確邊界的文件才調高。
HTML 大小上限5,000,000 位元組。對公開的 endpoint 應調低。
沙箱已啟用。僅在容器限制要求且主機已隔離時才停用。
高度當 heightPt <= 0 時自動計算。對於嚴格的版面契約,請使用固定高度。
外部資源由 renderer 政策封鎖。僅在經過審查的資源政策下才允許。
  • 繪製測試涵蓋具代表性的 HTML 與 CSS。
  • 安全測試涵蓋過大的 HTML,以及被封鎖的資源存取嘗試。
  • 匯入測試會斷言回傳的 form 物件具備內容、media box 與資源。
  • parser 測試涵蓋 xref table、xref stream、object stream 與格式錯誤的測試夾具案例。
  • worker 測試會呼叫 close() 並驗證沒有瀏覽器行程殘留。
  • 效能測試會依範本與內容大小記錄繪製時間。