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缺漏或非字串時,靜默地以''取代。請在你的啟動路徑中驗證設定來源。
URL 與位址(SSRF)失敗
標題為「URL 與位址(SSRF)失敗」的區段這些錯誤來自安全性原則,用以防範伺服器端請求偽造(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。
“File not found or not readable: ”
標題為「“File not found or not readable: ”」的區段- 型別:
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 上傳的檔名,而非作為路徑。
“Unknown office format extension: ”
標題為「“Unknown office format extension: ”」的區段- 型別:
ValueError - 觸發條件:副檔名不是
docx、xlsx、pptx、odt、ods、odp其中之一(不分大小寫,可容許前導點號)。 - 修正:只轉換這六種可辨識的格式。橋接器不會辨識舊版二進位格式(
.doc、.xls、.ppt)、.rtf、.csv、純文字或影像。在你呼叫橋接器之前,請先將這些輸入轉換為可辨識的格式,或透過另一條路徑處理它們。
傳輸與回應失敗
標題為「傳輸與回應失敗」的區段這些全都是 GotenbergConvertException。
“Gotenberg HTTP request failed: ”
標題為「“Gotenberg HTTP request failed: ”」的區段- 觸發條件:PSR-18 用戶端(或啟用 cURL pin 的傳輸)在送出請求時拋出。原因是連線被拒、逾時、TLS 交握失敗,或 pin 不相符。
- 例外代碼:底層用戶端例外的代碼。
- 原因:原始的 PSR-18 用戶端例外會以前一個例外(previous exception)的形式附加。
- 修正:請檢查四件事:以
isAvailable()檢查服務是否可達、檢查網路路徑、檢查 TLS 鏈;此外,若已設定 pinning,請檢查伺服器目前的 SubjectPublicKeyInfo(SPKI)是否與某個已設定的 pin 相符。憑證輪替後 pin 不相符是最典型的原因。輪替程序請參閱 /integrations/gotenberg/security-and-operations/.
“cURL transport error (): ”
標題為「“cURL transport error (): ”」的區段- 觸發條件:啟用 cURL pin 的傳輸在
curl_exec以非零的 cURL 錯誤編號失敗,或回傳了非字串主體。 - 修正:cURL 錯誤編號可指明原因(TLS、解析、逾時、pin)。當
CURLOPT_PINNEDPUBLICKEY拒絕憑證時,pinning 失敗會在此顯現。請確認已設定的 pin 與解析後的位址都是最新的。
“Gotenberg conversion failed with HTTP : ”
標題為「“Gotenberg conversion failed with HTTP : ”」的區段- 觸發條件:回應狀態不是
200。回應主體會納入訊息,並截斷至前 500 個字元;超過時會附上省略號。 - 修正:讀取訊息中納入的回應主體。Gotenberg 的錯誤訊息會說明轉換被拒的原因:不支援的文件內容、內部 LibreOffice 失敗,或
401或403的驗證被拒。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”」的區段- 觸發條件:狀態
200、Content-Type可接受,但主體並未以%PDF簽章開頭。 - 修正:上游回傳的內容雖然標頭如此,實際上卻不是 PDF。請將該回應視為不可信,並調查該服務。請勿將該主體寫入磁碟。橋接器拒絕將它作為結果回傳。
Pin 設定失敗
標題為「Pin 設定失敗」的區段”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 產生該值,而非從整張憑證產生。
“It says unavailable but the service is up”
標題為「“It says unavailable but the service is up”」的區段當 URL 為空、非 HTTPS,或解析到 private/reserved 位址時,isAvailable() 會在不發出任何網路呼叫的情況下回傳 false。它也會在任何網路錯誤時,或當 /health 回傳 500 或以上時回傳 false;在這些情況下,它會捕捉錯誤而非拋出。請依序檢查:
- 所設定的 URL 為非空且為 HTTPS。
- 主機不會解析到 private/reserved 位址(即使是探測,SSRF 防護也會拒絕它)。
<apiUrl>/health可從應用程式主機觸及,且回傳低於500的狀態。
另請參閱
標題為「另請參閱」的區段- /integrations/gotenberg/configuration/ — 每個選項與傳輸選擇規則。
- /integrations/gotenberg/production-usage/ — 重試原則與失敗處理契約。
- /integrations/gotenberg/security-and-operations/ — SSRF 模型與 pin 輪替。
- /integrations/gotenberg/quickstart/ — 情境中的完整 catch 順序。