Устранение неполадок NextPDF Gotenberg
Краткий обзор
Заголовок раздела «Краткий обзор»Мост сообщает о сбоях явно и как можно раньше. Каждый сбой порождает типизированное исключение с сообщением, в котором указана причина. Используйте эту страницу как каталог: для каждого сбоя приведены тип исключения, фрагмент сообщения, которое вы увидите, точный триггер в пути выполнения кода и способ исправления.
Семейства исключений:
GotenbergConvertException— сбой на уровне преобразования (конфигурация, транспорт или ответ).RuntimeException— сбой на уровне проверки, который политика безопасности порождает до любого сетевого трафика.ValueError— нераспознанное расширение файла.InvalidSpkiPinException— некорректная строка SubjectPublicKeyInfo (SPKI) pin для Transport Layer Security (TLS).
Сбои конфигурации
Заголовок раздела «Сбои конфигурации»Сообщение: “Invalid Gotenberg configuration: apiUrl is empty”
Заголовок раздела «Сообщение: “Invalid Gotenberg configuration: apiUrl is empty”»- Тип:
GotenbergConvertException - Триггер: вы вызвали
convertFile()илиconvertString(), когдаGotenbergConfig::isValid()возвращает false. Это происходит, если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”»- Триггер: хост является приватным или зарезервированным литералом Internet Protocol (IP) либо именем хоста, которое разрешается (по всем записям A/AAAA) в любой приватный или зарезервированный адрес. Это блокирует приватные диапазоны из Request for Comments (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”»- Триггер: между первоначальной проверкой и запросом новое разрешение Domain Name System (DNS) вернуло адрес, которого не было в первоначально проверенном наборе.
- Исправление: сработала защита time-of-check/time-of-use. Проверьте DNS для этого хоста. Допустимая причина — балансировщик нагрузки, который чередует адреса. Вредоносная причина — атака с подменой 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: ”»- Триггер: клиент PHP Standard Recommendation 18 (PSR-18) (или транспорт с привязкой через cURL) выбросил исключение при отправке запроса. Причина — отказ в соединении, тайм-аут, сбой TLS-рукопожатия или несоответствие pin.
- Код исключения: код базового исключения клиента.
- Причина: исходное исключение клиента PSR-18 присоединено как предыдущее исключение.
- Исправление: проверьте четыре вещи: доступность сервиса с помощью
isAvailable(), сетевой путь, цепочку TLS и, если настроена привязка (pinning), совпадение текущего SubjectPublicKeyInfo (SPKI) сервера с настроенным pin. Несоответствие pin после смены сертификата — классическая причина. См. процедуру смены в /integrations/gotenberg/security-and-operations/.
Сообщение: “cURL transport error (): ”
Заголовок раздела «Сообщение: “cURL transport error (): ”»- Триггер:
curl_execтранспорта с привязкой через cURL завершился с ненулевым номером ошибки cURL или вернул не строковое тело. - Исправление: номер ошибки cURL указывает причину (TLS, разрешение, тайм-аут, pin). Сбой привязки проявляется здесь, когда
CURLOPT_PINNEDPUBLICKEYотклоняет сертификат. Убедитесь, что настроенные 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. - Исправление: обычно это означает, что прокси или шлюз вернул HTML-страницу с ошибкой или перенаправлением со статусом
200. Мост намеренно отключает следование за перенаправлениями на привязанном транспорте, поэтому ответ3xxне может молча увести запрос к непроверенному хосту. Тело с невернымContent-Typeуказывает, что между вами и 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. - Исправление: вышестоящий сервис вернул данные, которые не являются файлом Portable Document Format (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”»isAvailable() возвращает false без какого-либо сетевого вызова, когда URL пуст, не использует HTTPS или разрешается в private/reserved адрес. Он также возвращает false при любой сетевой ошибке или когда /health возвращает 500 или выше; в этих случаях он перехватывает ошибку, а не выбрасывает её. Проверьте по порядку:
- Настроенный 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/ — исчерпывающий порядок перехвата в контексте.