跳到內容

Artisan 疑難排解

每一種 bridge 失敗都會以具型別的例外呈現。請將例外與訊息對照下方表格。每一列都指向確切的原始檢查,讓你修正成因,而不是症狀。

chrome-php/chrome is not installed. Install it via: composer require chrome-php/chrome:^1.15

CDP 用戶端函式庫不在 autoloader 中。BrowserPool::getBrowser() 會在任何一次 Chrome 啟動之前就拋出這個例外。請執行安裝指令。這與缺少執行檔不同:函式庫檢查與執行檔檢查是兩個彼此獨立的階段。

Chrome renderer failed: <cause>

Chrome 無法啟動、逾時或當機。前一個例外會保留原始成因。常見成因:

  • **找不到執行檔/無法執行。**請以 chromium --headless --dump-dom about:blank 驗證。將 chrome_binary 設為絕對路徑。
  • **Sandbox 無法初始化(容器環境)。**成因會提到 sandbox 或 namespace。佈建一個支援 sandbox 的容器(建議做法),或閱讀 /integrations/artisan/security-and-operations/. 一節後設定 no_sandbox: true
  • **逾時。**沉重的文件超過了 render_timeout。請為該工作負載調高逾時,或縮減文件;在面向使用者的路徑上,必須權衡 denial-of-service 的取捨。
  • **缺少共用函式庫。**Chrome 會立即結束。請安裝該發行版的 Chrome 相依套件集。

Chrome printToPDF returned empty data

Chrome 已啟動,但 printToPDF 回傳了零位元組。常見成因是輸入未產生任何可繪製的方塊(body 為空、所有內容皆為 display:none),或 Chrome 在列印途中當機。請確認該 HTML 會繪製出可見方塊,並檢查主機的記憶體壓力。

RuntimeException — 在 Chrome 之前就拒絕輸入

標題為「RuntimeException — 在 Chrome 之前就拒絕輸入」的區段
訊息包含成因修正方式
exceeds maximum allowed sizeHTML 超過 maxHtmlSize縮減輸入,或調高 max_html_size(會擴大資源耗盡的攻擊面)
oversized base64 data URI內嵌的 base64 ≥ 13 MB縮小內嵌資產;改為引用較小的影像
forbidden meta refresh redirect<meta http-equiv="refresh"> 存在移除該標籤;這是 SSRF 導向的導覽向量,一律會被拒絕

這些都來自 ChromeSecurityPolicy::validate(),並且會在接觸 Chrome 之前觸發,所以測試時可以快速且低成本地命中。

Page <n> has no content stream

Chrome 產生的 PDF 讓 parser 無法從中取出頁面。這種情況很罕見,通常代表 Chrome 輸出有缺陷,或某個 Chrome 版本產生了非預期的結構。請擷取 Chrome 版本與該輸入,並確認該執行檔是受支援的 Chrome/Chromium 組建。

這不是 bug。bridge 會封鎖每一次子資源擷取(CSP default-src 'none' 再加上一道 CDP setBlockedURLs('*') 封鎖)。遠端的 <img>、樣式表、字型、指令碼與 iframe 都不會載入。請將資產以 data: URI 內嵌,並透過 defaultCss<style> 內嵌 CSS。請參閱 /integrations/artisan/security-and-operations/. 一節中的網路模型。

文件溢出到 Chrome 的第二頁,而 bridge 只匯入第 0 頁。原因不是自動調整高度的緩衝對異常高的回流而言太小,就是明確指定的高度太小。請提供依內容大小設定的明確高度,或移除明確高度,改用帶有安全緩衝的自動調整高度。請參閱 /integrations/artisan/production-usage/. 一節中的高度處理。

這是預期行為。BrowserPool 每 100 次繪製就會重啟 Chrome 一次,以限制記憶體用量。一筆 notice 等級的日誌會記錄這次重啟及繪製次數。請在 SLO 中將它視為已知的週期性成本,而不是異常事件。重啟頻率高於每 100 次繪製一次,代表文件比預期更沉重。

BrowserPool 透過每 100 次繪製重啟一次來限制增長,但存活時間很長的 worker 仍可能累積記憶體。請在大批次之間呼叫 close() 以提早回收 Chrome 行程,並在主機的記憶體限制內執行該 worker。

  1. 用一段最小的可信 HTML 片段重現問題,以便隔離輸入與環境。
  2. 以 worker 使用者的身分,在主機上執行 chromium --headless --dump-dom about:blank
  3. 注入 PSR-3 logger,並讀取 info/notice 等級的日誌(執行檔路徑、重啟次數)。
  4. 確認 chrome-php/chrome 已安裝:若 BrowserPool::getBrowser() 不會拋出 ChromeNotAvailableException,即代表已安裝。
  5. 檢查該例外的前一個例外,找出底層的 Chrome 成因。
  • 安裝指南:/integrations/artisan/install/
  • 組態設定:/integrations/artisan/configuration/
  • 安全性與維運:/integrations/artisan/security-and-operations/
  • Chrome 繪製器設定:/integrations/artisan/chrome-renderer-setup/
  • 生產環境使用:/integrations/artisan/production-usage/