문제 해결
한눈에 보기
섹션 제목: “한눈에 보기”이 브리지는 세 가지 유형의 예외를 발생시킵니다. 포착한 예외는 무엇이 실패했는지와 재시도 또는 폴백이 적절한지를 알려줍니다. 아래의 모든 메시지 조각은 소스에서 인용한 것입니다.
예외 계층 구조
섹션 제목: “예외 계층 구조”| 예외 | 상속 | 의미 |
|---|---|---|
CloudflareNotAvailableException | NextPDF\Exception\NextPdfException | 엣지에 도달할 수 없거나 구성이 불완전하고, 사용 가능한 폴백이 없습니다. |
CloudflareRenderException | NextPDF\Exception\NextPdfException | Worker는 응답했지만 렌더링이 실패했습니다(HTTP 오류 또는 형식이 잘못된 본문). 절대 폴백하지 않습니다. |
InvalidSpkiPinException | InvalidArgumentException | 구성된 SPKI 핀 문자열의 형식이 잘못되었습니다. |
CloudflareSecurityPolicy는 입력 및 URL 정책 위반이 있으면 RuntimeException도 직접 발생시킵니다. 이는 요청이 전송되기 전에 발생합니다.
구성 및 입력 실패
섹션 제목: “구성 및 입력 실패”| 메시지 조각 | 발생 위치 | 원인 | 해결 방법 |
|---|---|---|---|
incomplete (missing worker_url or api_token) | 렌더러(폴백 경로 경유) | workerUrl 또는 apiToken이 비어 있음 | 둘 다 설정하고 isValid()로 확인하십시오. |
HTML input exceeds maximum size | CloudflareSecurityPolicy::validate() | HTML이 maxHtmlSize보다 큼 | 입력을 줄이거나 maxHtmlSize를 의도적으로 높이십시오. |
Base64 data URI exceeds safety limit | CloudflareSecurityPolicy::validate() | data:;base64, URI가 13631488 바이트를 초과하는 것으로 추정됨 | 자산은 외부로 분리하십시오. 큰 바이너리를 인라인하지 마십시오. |
meta-refresh redirect which could cause SSRF | CloudflareSecurityPolicy::validate() | <meta http-equiv="refresh"> 태그 | 태그를 제거하십시오. 렌더링되는 HTML 외부에서 서버 측 리디렉션을 사용하십시오. |
Invalid Worker URL | validateWorkerUrl() | URL이 파싱되지 않거나 scheme/host가 없음 | 완전한 절대 HTTPS URL을 제공하십시오. |
Worker URL must use HTTPS | validateWorkerUrl() | HTTPS가 아닌 스킴 | https://를 사용하십시오. |
private or reserved IP addresses | validateWorkerUrl() | RFC 1918 / 루프백 / RFC 3927 범위의 IP 리터럴 | 공용 엔드포인트를 가리키도록 하십시오. |
hostname resolves to a private or reserved IP | validateWorkerUrl() | 확인된 A/AAAA 레코드가 private/reserved 범위임 | DNS를 수정하십시오. 리바인딩 가능성을 조사하십시오. |
DNS answer changed since validation | assertPinsStillValid() | 확인과 전송 사이에 호스트가 새 IP로 확인되었음 | 다시 확인하십시오. 가능한 리바인딩 시도로 취급하십시오. |
Worker 측 실패
섹션 제목: “Worker 측 실패”이는 CloudflareRenderException입니다. Worker는 응답했지만 렌더링 자체가 실패한 경우입니다. 이 경우에는 로컬 폴백이 절대 트리거되지 않습니다 — 엣지에는 도달할 수 있었기 때문입니다.
| 메시지 조각 | 원인 |
|---|---|
Cloudflare Worker returned HTTP <code>: <detail> | 200이 아닌 상태입니다. 세부 정보는 JSON error 필드 또는 본문 처음 200 바이트입니다. |
Worker returned empty or invalid PDF data | %PDF로 시작하지 않는 바이너리 응답입니다. |
Worker error: <message> | error 필드를 포함한 JSON 응답입니다. |
JSON response missing "pdf" field | pdf 필드가 없는 JSON 응답입니다. |
Invalid base64-encoded PDF in JSON response | pdf 필드의 base64 디코딩 결과가 %PDF로 시작하는 바이트가 아닙니다. |
Invalid JSON response from Worker | Content-Type: application/json이지만 본문이 배열로 디코딩되지 않았습니다. |
Unexpected Content-Type from Worker: <type> | Content-Type이 application/pdf도 application/json도 아닌 200입니다. |
이 중 하나를 포착했다면 Worker 로그를 검사하십시오. 실패 원인은 이 브리지가 아니라 Worker 측에 있습니다.
도달성 및 폴백 실패
섹션 제목: “도달성 및 폴백 실패”이는 CloudflareNotAvailableException입니다. 엣지를 사용할 수 없었고, 어떤 폴백도 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을 실행하고 팩토리를 연결하십시오. |
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 수준 실패(TLS, DNS, 타임아웃) | cURL 오류 번호를 검사하십시오. 핀이 설정되어 있다면, 제공된 SPKI가 여전히 핀에 고정되어 있는지 확인하십시오. |
| 인증서 교체 직후 렌더링이 즉시 실패함 | 새 인증서의 SPKI가 핀 세트에 없음 | 교체하기 전에 새 SPKI를 백업 핀으로 추가하십시오. |
| 핀이 구성되어 있는데도 핀 고정 전송이 사용되지 않음 | PSR-17 ResponseFactory가 제공되지 않음 | ResponseFactory를 전달하십시오. 핀 고정 전송에는 이것이 필요합니다. |
isAvailable() 동작
섹션 제목: “isAvailable() 동작”isAvailable()은 절대 예외를 던지지 않습니다. 구성이 유효하지 않거나 HEAD 프로브가 실패하거나 예외를 발생시키면 false를 반환합니다. 프로브가 500 미만의 상태 코드로 응답할 때만 true를 반환합니다. true 결과는 힌트일 뿐입니다. 이후 POST는 위의 Worker 측 오류 중 어떤 것으로도 여전히 실패할 수 있습니다. 통과한 프로브를 보장으로 취급하지 마십시오.
속도 제한 관련 의외의 상황
섹션 제목: “속도 제한 관련 의외의 상황”ApiProtection 제한기는 프로세스별 인메모리 방식입니다. 카운트는 재시작 후 유지되지 않으며, 워커나 노드 간에 공유되지 않습니다. 따라서 어떤 클라이언트가 한 노드에서는 허용되고 다른 노드에서는 거부되는 것을 보더라도 이는 예상된 동작입니다. 클러스터 전체에 적용되는 제한이 필요하면 제한기 앞에 공유 저장소를 두십시오.
관련 항목
섹션 제목: “관련 항목”- /integrations/cloudflare/security-and-operations/ — 운영 런북과 이러한 메시지의 근거가 되는 제어 장치입니다.
- /integrations/cloudflare/quickstart/ — 표준 try/catch 형태입니다.
- /integrations/cloudflare/production-usage/ — 폴백 연결 방식의 세부 정보입니다.