การแก้ไขปัญหา
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”บริดจ์สามารถเกิด exception ได้สามชนิด exception ที่คุณดักจับได้จะบอกว่าส่วนใดล้มเหลว และควรลองใหม่หรือเปลี่ยนไปใช้ fallback หรือไม่ ส่วนของข้อความที่ตรงกันแต่ละรายการด้านล่างมาจากซอร์สโค้ด
ลำดับชั้นของ exception
หัวข้อที่มีชื่อว่า “ลำดับชั้นของ exception”| ข้อยกเว้น (Exception) | สืบทอดจาก | ความหมาย |
|---|---|---|
CloudflareNotAvailableException | NextPDF\Exception\NextPdfException | บริดจ์เข้าถึง edge ไม่ได้ หรือการกำหนดค่าไม่ครบถ้วน และไม่มี fallback ที่ใช้งานได้ |
CloudflareRenderException | NextPDF\Exception\NextPdfException | Worker ตอบกลับแล้ว แต่การเรนเดอร์ล้มเหลว (Hypertext Transfer Protocol (HTTP) error หรือ body ที่มีรูปแบบไม่ถูกต้อง) โดยจะไม่ใช้ fallback |
InvalidSpkiPinException | InvalidArgumentException | สตริง SPKI pin (Subject Public Key Info) ที่กำหนดค่าไว้ไม่อยู่ในรูปแบบที่ถูกต้อง |
CloudflareSecurityPolicy ยังทำให้เกิด RuntimeException โดยตรงเมื่ออินพุตหรือ Uniform Resource Locator (URL) ละเมิดนโยบายด้วย โดย exception จะเกิดขึ้นก่อนส่งคำขอใดๆ
ความล้มเหลวด้านการกำหนดค่าและอินพุต
หัวข้อที่มีชื่อว่า “ความล้มเหลวด้านการกำหนดค่าและอินพุต”| ส่วนของข้อความ | เกิดโดย | สาเหตุ | วิธีแก้ไข |
|---|---|---|---|
incomplete (missing worker_url or api_token) | Renderer (ผ่าน fallback path) | workerUrl หรือ apiToken อย่างใดอย่างหนึ่งว่างเปล่า | กำหนดค่าทั้งสองรายการ แล้วตรวจสอบด้วย isValid() |
HTML input exceeds maximum size | CloudflareSecurityPolicy::validate() | อินพุต Hypertext Markup Language (HTML) มีขนาดเกิน maxHtmlSize | ลดขนาดอินพุตหรือเพิ่มค่า maxHtmlSize อย่างจงใจ |
Base64 data URI exceeds safety limit | CloudflareSecurityPolicy::validate() | URI แบบ data:;base64, (Uniform Resource Identifier) ถูกประเมินว่ามีขนาดเกิน 13631488 ไบต์ | แยกแอสเซ็ตออกไปไว้ภายนอก อย่าฝังไบนารีขนาดใหญ่แบบ inline |
meta-refresh redirect which could cause SSRF | CloudflareSecurityPolicy::validate() | แท็ก <meta http-equiv="refresh"> อาจก่อให้เกิด server-side request forgery (SSRF) | ลบแท็กออก แล้วใช้การ redirect ฝั่งเซิร์ฟเวอร์ภายนอก HTML ที่เรนเดอร์แทน |
Invalid Worker URL | validateWorkerUrl() | URL แยกวิเคราะห์ไม่ได้ หรือขาด scheme/host | ระบุ URL แบบสัมบูรณ์ที่สมบูรณ์ซึ่งใช้ Hypertext Transfer Protocol Secure (HTTPS) |
Worker URL must use HTTPS | validateWorkerUrl() | scheme ไม่ใช่ HTTPS | ใช้ https:// แทน |
private or reserved IP addresses | validateWorkerUrl() | ค่า Internet Protocol (IP) literal อยู่ในช่วง Request for Comments (RFC) 1918 / loopback / RFC 3927 | ชี้ไปยัง endpoint สาธารณะ |
hostname resolves to a private or reserved IP | validateWorkerUrl() | เรกคอร์ด A/AAAA ของ Domain Name System (DNS) ถูก resolve เป็น private หรือ reserved | แก้ไข DNS และตรวจสอบความเป็นไปได้ของการ rebinding |
DNS answer changed since validation | assertPinsStillValid() | โฮสต์ถูก resolve เป็นที่อยู่ IP ใหม่ระหว่างการตรวจสอบกับการส่ง | resolve ใหม่ และถือว่าเป็นความพยายาม rebinding ที่อาจเกิดขึ้น |
ความล้มเหลวฝั่ง Worker
หัวข้อที่มีชื่อว่า “ความล้มเหลวฝั่ง Worker”รายการเหล่านี้เป็นความล้มเหลวแบบ CloudflareRenderException Worker ตอบกลับแล้ว แต่การเรนเดอร์ล้มเหลวเอง รายการเหล่านี้จะไม่กระตุ้น fallback ในเครื่องเลย เพราะยังเข้าถึง edge ได้
| ส่วนของข้อความ | สาเหตุ |
|---|---|
Cloudflare Worker returned HTTP <code>: <detail> | สถานะที่ไม่ใช่ 200 รายละเอียดมาจากฟิลด์ error ของ JavaScript Object Notation (JSON) หรือ 200 ไบต์แรกของ body |
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 | ฟิลด์ pdf ไม่สามารถ base64-decode ได้เป็นไบต์ที่ขึ้นต้นด้วย %PDF ตามที่ต้องการ |
Invalid JSON response from Worker | body ใช้ Content-Type: application/json แต่ไม่สามารถ decode เป็น array ได้ |
Unexpected Content-Type from Worker: <type> | การตอบกลับ 200 มี Content-Type ที่ไม่ใช่ทั้ง application/pdf หรือ application/json |
เมื่อคุณดักจับรายการใดรายการหนึ่งเหล่านี้ ให้ตรวจสอบล็อกของ Worker ความล้มเหลวอยู่ที่ฝั่ง Worker ไม่ใช่ในบริดจ์นี้
ความล้มเหลวของการเข้าถึงและ fallback
หัวข้อที่มีชื่อว่า “ความล้มเหลวของการเข้าถึงและ fallback”รายการเหล่านี้เป็นความล้มเหลวแบบ CloudflareNotAvailableException บริดจ์ใช้ edge ไม่ได้ และไม่มี fallback ใดสร้างไฟล์ Portable Document Format (PDF) ออกมา
| ส่วนของข้อความ | สาเหตุ | วิธีแก้ไข |
|---|---|---|
Cloudflare Worker unavailable: <reason> | transport error ขณะปิด fallback ไว้ | เปิดใช้ fallbackToLocal และเชื่อมต่อ factory หรือแก้ไขการเชื่อมต่อ |
Artisan is installed but no LocalRendererFactoryInterface was provided | nextpdf/artisan มีอยู่ แต่ไม่ได้ส่ง factory เข้ามา | ส่ง LocalRendererFactoryInterface เข้าไปยัง constructor |
local Chrome fallback (nextpdf/artisan) is not installed | เปิดใช้ fallback ไว้ ไม่ได้กำหนดค่า factory และไม่มี Artisan | เรียกใช้ composer require nextpdf/artisan แล้วเชื่อมต่อ factory |
เมื่อคุณจัดเตรียม logger แบบ PHP Standards Recommendation (PSR)-3 และ fallback path ทำงาน บริดจ์จะบันทึก warning (Cloudflare render failed, attempting fallback) แล้วตามด้วย info (Falling back to local renderer)
ความล้มเหลวของ transport / pinning
หัวข้อที่มีชื่อว่า “ความล้มเหลวของ transport / pinning”| อาการ | สาเหตุ | วิธีแก้ไข |
|---|---|---|
InvalidSpkiPinException: Invalid SPKI pin format | pin ไม่อยู่ในรูปแบบ sha256/<base64> (หรือ sha256//<base64>) | แก้ไขสตริง pin ให้ถูกต้อง |
cURL transport error (<n>): <msg> | ความล้มเหลวระดับ cURL (Transport Layer Security (TLS), DNS, timeout) | ตรวจสอบหมายเลข error ของ cURL หากตั้งค่า pin ไว้ ให้ยืนยันว่า SPKI ที่ให้บริการยังคงถูก pin อยู่ |
| การเรนเดอร์ล้มเหลวทันทีหลังการหมุนเวียนใบรับรอง | SPKI ของใบรับรองใหม่ไม่อยู่ในชุด pin | เพิ่ม SPKI ใหม่เป็น backup pin ก่อน หมุนเวียน |
| ไม่ได้ใช้ pinned transport แม้ว่าจะกำหนดค่า pin ไว้แล้ว | ไม่ได้จัดเตรียม ResponseFactory แบบ PSR-17 | ส่ง ResponseFactory เข้าไป เพราะ pinned transport ต้องใช้ค่านี้ |
การทำงานของ isAvailable()
หัวข้อที่มีชื่อว่า “การทำงานของ isAvailable()”isAvailable() จะไม่ throw เลย โดยจะคืนค่า false เมื่อการกำหนดค่าไม่ถูกต้อง หรือเมื่อการ probe แบบ HEAD ล้มเหลวหรือเกิด exception และจะคืนค่า true เฉพาะเมื่อการ probe ตอบกลับด้วยสถานะที่ต่ำกว่า 500 ผลลัพธ์ true เป็นเพียงสัญญาณบอกเบื้องต้นเท่านั้น คำขอ POST ที่ตามมายังคงล้มเหลวได้จาก error ฝั่ง Worker รายการใดก็ได้ที่กล่าวไว้ข้างต้น อย่าถือว่าการ probe ที่ผ่านเป็นการรับประกัน
สิ่งที่อาจคาดไม่ถึงเกี่ยวกับ rate-limit
หัวข้อที่มีชื่อว่า “สิ่งที่อาจคาดไม่ถึงเกี่ยวกับ rate-limit”ApiProtection เก็บค่าจำกัดไว้ในหน่วยความจำต่อโปรเซส ตัวนับจะไม่คงอยู่หลังการรีสตาร์ท และไม่ถูกแชร์ข้าม worker หรือ node หาก node หนึ่งอนุญาตไคลเอนต์แต่อีก node หนึ่งปฏิเสธ นั่นเป็นพฤติกรรมที่คาดไว้ ให้วาง shared store ไว้ด้านหน้าตัวจำกัดเพื่อให้ใช้ค่าจำกัดร่วมกันได้ทั่วทั้งคลัสเตอร์
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- /integrations/cloudflare/security-and-operations/ — runbook สำหรับการดำเนินงานและการควบคุมที่อยู่เบื้องหลังข้อความเหล่านี้
- /integrations/cloudflare/quickstart/ — รูปแบบ try/catch ที่เป็นมาตรฐาน
- /integrations/cloudflare/production-usage/ — รายละเอียดการเชื่อมต่อ fallback