Устранение неполадок
Мост вызывает три типа исключений. По перехваченному исключению понятно, что именно отказало и нужно ли повторить попытку или перейти на резервный путь. Каждый фрагмент сообщения ниже взят из исходного кода.
Иерархия исключений
Заголовок раздела «Иерархия исключений»| Исключение | Наследует | Значение |
|---|---|---|
CloudflareNotAvailableException | NextPDF\Exception\NextPdfException | Мост не может обратиться к периферии или конфигурация неполна, а пригодного резервного пути нет. |
CloudflareRenderException | NextPDF\Exception\NextPdfException | Worker ответил, но отрисовка не удалась (ошибка Hypertext Transfer Protocol (HTTP) или некорректное тело). Резервный путь никогда не запускается. |
InvalidSpkiPinException | InvalidArgumentException | Настроенная строка пина Subject Public Key Info (SPKI) имеет неверный формат. |
CloudflareSecurityPolicy также напрямую вызывает RuntimeException при нарушениях политики для входных данных и Uniform Resource Locator (URL). Исключение возникает до отправки любого запроса.
Сбои конфигурации и входных данных
Заголовок раздела «Сбои конфигурации и входных данных»| Фрагмент сообщения | Вызывается | Причина | Решение |
|---|---|---|---|
incomplete (missing worker_url or api_token) | renderer (по резервному пути) | workerUrl или apiToken пуст | Задайте оба значения, затем проверьте их через isValid(). |
HTML input exceeds maximum size | CloudflareSecurityPolicy::validate() | Входные данные Hypertext Markup Language (HTML) длиннее maxHtmlSize | Уменьшите объём входных данных или осознанно увеличьте maxHtmlSize. |
Base64 data URI exceeds safety limit | CloudflareSecurityPolicy::validate() | Расчётный размер Uniform Resource Identifier (URI) вида data:;base64, превышает 13631488 байт | Вынесите ресурс наружу; не встраивайте крупные бинарные данные. |
meta-refresh redirect which could cause SSRF | CloudflareSecurityPolicy::validate() | Тег <meta http-equiv="refresh"> может спровоцировать подделку запроса на стороне сервера (SSRF) | Удалите тег; используйте серверное перенаправление за пределами отрисовываемого HTML. |
Invalid Worker URL | validateWorkerUrl() | URL не разбирается или в нём нет scheme/host | Укажите полный абсолютный URL с Hypertext Transfer Protocol Secure (HTTPS). |
Worker URL must use HTTPS | validateWorkerUrl() | Схема не HTTPS | Используйте https://. |
private or reserved IP addresses | validateWorkerUrl() | IP-литерал Internet Protocol (IP) в диапазоне Request for Comments (RFC) 1918 / loopback / RFC 3927 | Укажите публичную конечную точку. |
hostname resolves to a private or reserved IP | validateWorkerUrl() | Разрешённая запись A/AAAA системы доменных имён Domain Name System (DNS) является частной или зарезервированной | Исправьте DNS; проверьте возможную атаку перепривязки (rebinding). |
DNS answer changed since validation | assertPinsStillValid() | Между проверкой и отправкой хост разрешился в новый IP-адрес | Повторите разрешение; рассматривайте это как возможную попытку перепривязки. |
Сбои на стороне Worker
Заголовок раздела «Сбои на стороне Worker»Это сбои CloudflareRenderException. Worker ответил, но сама отрисовка не удалась. Они никогда не запускают локальный резервный путь, потому что периферия была доступна.
| Фрагмент сообщения | Причина |
|---|---|
Cloudflare Worker returned HTTP <code>: <detail> | Статус, отличный от 200. Подробности берутся из поля error JavaScript Object Notation (JSON) или из первых 200 байт тела ответа. |
Worker returned empty or invalid PDF data | Бинарный ответ не начинается с %PDF. |
Worker error: <message> | Ответ JSON, который содержит поле error. |
JSON response missing "pdf" field | Ответ JSON без поля pdf. |
Invalid base64-encoded PDF in JSON response | После декодирования из base64 поле pdf не даёт байты, начинающиеся с %PDF. |
Invalid JSON response from Worker | Тело использует Content-Type: application/json, но не декодируется в массив. |
Unexpected Content-Type from Worker: <type> | Ответ 200, у которого Content-Type не является ни application/pdf, ни application/json. |
Если вы перехватили один из этих сбоев, проверьте журналы Worker. Сбой произошёл на стороне Worker, а не в этом мосте.
Сбои доступности и резервного пути
Заголовок раздела «Сбои доступности и резервного пути»Это сбои CloudflareNotAvailableException. Мост не смог воспользоваться периферией, и ни один резервный путь не создал файл Portable Document Format (PDF).
| Фрагмент сообщения | Причина | Решение |
|---|---|---|
Cloudflare Worker unavailable: <reason> | Ошибка транспорта при отключённом резервном пути | Включите fallbackToLocal и подключите фабрику либо исправьте подключение. |
Artisan is installed but no LocalRendererFactoryInterface was provided | nextpdf/artisan установлен, но фабрика не передана | Передайте LocalRendererFactoryInterface в конструктор. |
local Chrome fallback (nextpdf/artisan) is not installed | Резервный путь включён, фабрика не настроена, и Artisan отсутствует | Выполните composer require nextpdf/artisan, затем подключите фабрику. |
Если вы передали журналировщик PHP Standards Recommendation (PSR)-3 и сработал резервный путь, мост записывает warning (Cloudflare render failed, attempting fallback), затем info (Falling back to local renderer).
Сбои транспорта / закрепления пинов
Заголовок раздела «Сбои транспорта / закрепления пинов»| Симптом | Причина | Решение |
|---|---|---|
InvalidSpkiPinException: Invalid SPKI pin format | Пин не соответствует форме sha256/<base64> (или sha256//<base64>) | Исправьте строку пина. |
cURL transport error (<n>): <msg> | Сбой на уровне cURL (Transport Layer Security (TLS), DNS, тайм-аут) | Проверьте номер ошибки cURL; если пины заданы, убедитесь, что предъявленный SPKI всё ещё закреплён. |
| Отрисовка сразу же не удаётся после ротации сертификата | SPKI нового сертификата отсутствует в наборе пинов | Добавьте новый SPKI как резервный пин до ротации. |
| Закреплённый транспорт не используется, несмотря на настроенные пины | Не передан ResponseFactory в формате PSR-17 | Передайте ResponseFactory; закреплённому транспорту он необходим. |
isAvailable(): поведение
Заголовок раздела «isAvailable(): поведение»isAvailable() никогда не выбрасывает исключение. Он возвращает false, когда конфигурация неверна либо проба HEAD не удаётся или вызывает исключение. Он возвращает true только тогда, когда проба отвечает статусом ниже 500. Результат true — лишь подсказка: последующий POST всё ещё может завершиться любой из приведённых выше ошибок на стороне Worker. Не считайте успешную пробу гарантией.
Неожиданности с ограничением частоты
Заголовок раздела «Неожиданности с ограничением частоты»ApiProtection хранит ограничения в памяти процесса. Счётчики не сохраняются после перезапуска и не разделяются между воркерами или узлами. Если один узел разрешает клиента, а другой ему отказывает, это ожидаемо. Поставьте общее хранилище перед ограничителем, чтобы ограничение работало в масштабе кластера.
См. также
Заголовок раздела «См. также»- /integrations/cloudflare/security-and-operations/ — операционное руководство и средства контроля, стоящие за этими сообщениями.
- /integrations/cloudflare/quickstart/ — канонический шаблон try/catch.
- /integrations/cloudflare/production-usage/ — детали подключения резервного пути.