跳到內容

NextPDF Gotenberg 疑難排解

橋接器會及早且明確地失敗。每一次失敗都是帶有型別的例外,其訊息會指出原因。本頁就是這份失敗目錄。針對每一種失敗,本頁會列出例外型別、你會看到的訊息片段、程式碼路徑中的確切觸發條件,以及修正方式。

例外家族如下:

  • GotenbergConvertException — 轉換層失敗(設定、傳輸或回應)。
  • RuntimeException — 由安全性原則在任何網路流量之前拋出的驗證層失敗。
  • ValueError — 無法辨識的副檔名。
  • InvalidSpkiPinException — 格式錯誤的 TLS pin 字串。

”Invalid Gotenberg configuration: apiUrl is empty”

標題為「”Invalid Gotenberg configuration: apiUrl is empty”」的區段
  • 型別GotenbergConvertException
  • 觸發條件:在 GotenbergConfig::isValid() 為 false 時呼叫了 convertFile()convertString()。這會在 apiUrl 為空字串時發生。
  • 修正:提供一個非空的 HTTPS URL。若你以 fromArray() 建立設定,請注意它會在 api_url 缺漏或非字串時,靜默地以 '' 取代。請在你的啟動路徑中驗證設定來源。

這些錯誤來自安全性原則,用以防範伺服器端請求偽造(SSRF)。它們會在送出任何請求之前拋出,而且都是單純的 RuntimeException

“Gotenberg API URL must use HTTPS (got: http)”

標題為「“Gotenberg API URL must use HTTPS (got: http)”」的區段
  • 觸發條件:設定的 URL 配置不是 https。此檢查不分大小寫,因此 HTTPS:// 會被接受。
  • 修正:在 Gotenberg 前方放置 TLS,並設定 HTTPS 端點。即使是本機開發,純 HTTP 也會被拒絕。

“Invalid Gotenberg API URL: unable to parse”

標題為「“Invalid Gotenberg API URL: unable to parse”」的區段
  • 觸發條件:該 URL 無法解析為配置與主機。
  • 修正:提供一個語法上有效的絕對 URL,例如 https://gotenberg.example.com:3000

“Gotenberg API URL must not resolve to a private or reserved IP address”

標題為「“Gotenberg API URL must not resolve to a private or reserved IP address”」的區段
  • 觸發條件:主機是私有或保留的 IP 文字位址,是一個(透過所有 A/AAAA 記錄)解析到任何私有或保留位址的主機名稱。這會封鎖 RFC 1918 範圍、loopback 以及 link-local 位址。
  • 修正:將橋接器指向可路由的公開位址,或經適當網段切分的服務位址。若你的 Gotenberg 刻意位於私有網路上,橋接器的 SSRF 防護會依設計予以拒絕。請透過防護所接受的位址來公開它,然後改以網路控管與驗證保護該路徑。請參閱 /integrations/gotenberg/security-and-operations/.

”Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack”

標題為「”Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack”」的區段
  • 觸發條件:在初次驗證與發出請求之間,新的 DNS 解析回傳了不在原先已驗證集合中的位址。
  • 修正:這表示 time-of-check/time-of-use 防護被觸發。請調查該主機的 DNS。正當原因可能是負載平衡器正在輪替位址;惡意原因則可能是重新繫結(rebinding)攻擊。請為 Gotenberg 端點使用穩定的位址,或使用記錄集穩定的名稱。

這些錯誤由安全性原則在請求之前拋出。除非另有說明,每一個都是單純的 RuntimeException

  • 型別GotenbergConvertException
  • 觸發條件convertFile() 無法將路徑正規化,或解析後的路徑不是可讀的一般檔案。目錄也會觸發此情形。
  • 修正:傳入一個指向既有且可讀檔案的路徑。該路徑會先以 realpath() 正規化,這也能阻止路徑穿越。

“File size ( bytes) exceeds maximum allowed size ( bytes)”

標題為「“File size ( bytes) exceeds maximum allowed size ( bytes)”」的區段
  • 觸發條件:輸入大於 maxFileSize(預設 52,428,800 位元組 = 50 MiB)。
  • 修正:若文件確實需要更大的上限,請提高 maxFileSize,或在上游就拒絕該上傳。請把上限維持在實際文件需求允許的最低值。它是橋接器唯一內建的資源界限。

檔名會經過篩檢。對於檔案轉換,檔名是解析後路徑的基本名稱;對於 convertString(),則是你傳入的名稱。以下每一項都是 RuntimeException

訊息片段觸發條件
must not be empty空白的檔名
path traversal sequences (..)名稱包含 ..
forward slashes名稱包含 /
backslashes名稱包含 \
null bytes名稱包含一個 NUL 位元組
control characters名稱包含一個 ASCII 控制字元(0–31)
  • 修正:傳入一個乾淨的基本名稱。對於 convertString(),請提供一個單純的名稱,例如 report.docx。它用於格式偵測,以及作為 multipart 上傳的檔名,而非作為路徑。
  • 型別ValueError
  • 觸發條件:副檔名不是 docxxlsxpptxodtodsodp 其中之一(不分大小寫,可容許前導點號)。
  • 修正:只轉換這六種可辨識的格式。橋接器不會辨識舊版二進位格式(.doc.xls.ppt)、.rtf.csv、純文字或影像。在你呼叫橋接器之前,請先將這些輸入轉換為可辨識的格式,或透過另一條路徑處理它們。

這些全都是 GotenbergConvertException

  • 觸發條件:PSR-18 用戶端(或啟用 cURL pin 的傳輸)在送出請求時拋出。原因是連線被拒、逾時、TLS 交握失敗,或 pin 不相符。
  • 例外代碼:底層用戶端例外的代碼。
  • 原因:原始的 PSR-18 用戶端例外會以前一個例外(previous exception)的形式附加。
  • 修正:請檢查四件事:以 isAvailable() 檢查服務是否可達、檢查網路路徑、檢查 TLS 鏈;此外,若已設定 pinning,請檢查伺服器目前的 SubjectPublicKeyInfo(SPKI)是否與某個已設定的 pin 相符。憑證輪替後 pin 不相符是最典型的原因。輪替程序請參閱 /integrations/gotenberg/security-and-operations/.
  • 觸發條件:啟用 cURL pin 的傳輸在 curl_exec 以非零的 cURL 錯誤編號失敗,或回傳了非字串主體。
  • 修正:cURL 錯誤編號可指明原因(TLS、解析、逾時、pin)。當 CURLOPT_PINNEDPUBLICKEY 拒絕憑證時,pinning 失敗會在此顯現。請確認已設定的 pin 與解析後的位址都是最新的。
  • 觸發條件:回應狀態不是 200。回應主體會納入訊息,並截斷至前 500 個字元;超過時會附上省略號。
  • 修正:讀取訊息中納入的回應主體。Gotenberg 的錯誤訊息會說明轉換被拒的原因:不支援的文件內容、內部 LibreOffice 失敗,或 401403 的驗證被拒。401/403 表示 apiKey 缺漏或錯誤。5xx 是服務端失敗,可列為有界重試的候選對象。

“Unexpected Content-Type from Gotenberg: (expected application/pdf)”

標題為「“Unexpected Content-Type from Gotenberg: (expected application/pdf)”」的區段
  • 觸發條件:狀態為 200,但回應的 Content-Type 不含 application/pdf
  • 修正:這通常表示某個 proxy 或閘道以 200 回傳了一個 HTML 錯誤頁或重新導向頁。橋接器在 pin 的傳輸上刻意停用重新導向跟隨,因此 3xx 不會被靜默追蹤到未經查核的主機。主體以錯誤型別送達,表示你與 Gotenberg 之間有東西在干擾。請檢查網路路徑。

“Response body does not start with %PDF header — invalid PDF data”

標題為「“Response body does not start with %PDF header — invalid PDF data”」的區段
  • 觸發條件:狀態 200Content-Type 可接受,但主體並未以 %PDF 簽章開頭。
  • 修正:上游回傳的內容雖然標頭如此,實際上卻不是 PDF。請將該回應視為不可信,並調查該服務。請勿將該主體寫入磁碟。橋接器拒絕將它作為結果回傳。

”Invalid SPKI pin format: (expected sha256/)”

標題為「”Invalid SPKI pin format: (expected sha256/)”」的區段
  • 型別InvalidSpkiPinException
  • 觸發條件:設定的 pin 字串不是以 sha256/sha256// 開頭。
  • 修正:將每個 pin 格式化為 sha256/<base64-encoded-spki-hash>。此傳輸也接受 cURL 原生的 sha256//<base64> 形式。請從伺服器憑證的 SubjectPublicKeyInfo 產生該值,而非從整張憑證產生。

當 URL 為空、非 HTTPS,或解析到 private/reserved 位址時,isAvailable() 會在不發出任何網路呼叫的情況下回傳 false。它也會在任何網路錯誤時,或當 /health 回傳 500 或以上時回傳 false;在這些情況下,它會捕捉錯誤而非拋出。請依序檢查:

  1. 所設定的 URL 為非空且為 HTTPS。
  2. 主機不會解析到 private/reserved 位址(即使是探測,SSRF 防護也會拒絕它)。
  3. <apiUrl>/health 可從應用程式主機觸及,且回傳低於 500 的狀態。
  • /integrations/gotenberg/configuration/ — 每個選項與傳輸選擇規則。
  • /integrations/gotenberg/production-usage/ — 重試原則與失敗處理契約。
  • /integrations/gotenberg/security-and-operations/ — SSRF 模型與 pin 輪替。
  • /integrations/gotenberg/quickstart/ — 情境中的完整 catch 順序。