การแก้ไขปัญหา Gotenberg ใน NextPDF
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”bridge จะล้มเหลวอย่างชัดเจนตั้งแต่เนิ่นๆ ทุกความล้มเหลวจะยก exception พร้อมชนิดที่ระบุและข้อความที่บอกสาเหตุ ใช้หน้านี้เป็นแคตาล็อกอ้างอิง สำหรับความล้มเหลวแต่ละกรณี คุณจะเห็นชนิดของ exception ส่วนของข้อความที่จะพบ เงื่อนไขที่กระตุ้นในเส้นทางโค้ดอย่างแน่นอน และวิธีแก้ไข
กลุ่มของ exception มีดังนี้
GotenbergConvertException— ความล้มเหลวในชั้นการแปลง (การกำหนดค่า การรับส่งข้อมูล หรือการตอบกลับ)RuntimeException— ความล้มเหลวในชั้นการตรวจสอบความถูกต้องที่นโยบายความปลอดภัยยกขึ้นก่อนที่จะมีการรับส่งข้อมูลทางเครือข่ายใดๆValueError— นามสกุลไฟล์ที่ไม่รู้จักInvalidSpkiPinException— สตริง pin ของ SubjectPublicKeyInfo (SPKI) ใน Transport Layer Security (TLS) ที่มีรูปแบบไม่ถูกต้อง
ความล้มเหลวของการกำหนดค่า
หัวข้อที่มีชื่อว่า “ความล้มเหลวของการกำหนดค่า”การกำหนดค่าไม่ถูกต้อง: “Invalid Gotenberg configuration: apiUrl is empty”
หัวข้อที่มีชื่อว่า “การกำหนดค่าไม่ถูกต้อง: “Invalid Gotenberg configuration: apiUrl is empty””- Type:
GotenbergConvertException - Trigger: คุณเรียก
convertFile()หรือconvertString()ในขณะที่GotenbergConfig::isValid()เป็น false กรณีนี้เกิดขึ้นเมื่อapiUrlเป็นสตริงว่าง - Fix: ระบุ URL แบบ HTTPS ที่ไม่เป็นค่าว่าง หากคุณสร้างการกำหนดค่าด้วย
fromArray()โปรดทราบว่าapi_urlที่ขาดหายไปหรือไม่ใช่สตริงจะถูกแทนที่ด้วย''โดยไม่แสดงสัญญาณใดๆ ตรวจสอบความถูกต้องของแหล่งที่มาของการกำหนดค่าระหว่างการบูต
ความล้มเหลวของ URL และที่อยู่ (SSRF)
หัวข้อที่มีชื่อว่า “ความล้มเหลวของ URL และที่อยู่ (SSRF)”ความล้มเหลวเหล่านี้มาจากนโยบายความปลอดภัยซึ่งป้องกัน server-side request forgery (SSRF) bridge จะยกความล้มเหลวเหล่านี้ขึ้นก่อนส่งคำขอใดๆ แต่ละรายการเป็น RuntimeException ธรรมดา
URL ต้องใช้ HTTPS: “Gotenberg API URL must use HTTPS (got: http)”
หัวข้อที่มีชื่อว่า “URL ต้องใช้ HTTPS: “Gotenberg API URL must use HTTPS (got: http)””- Trigger: scheme ของ URL ที่กำหนดค่าไว้ไม่ใช่
httpsการตรวจสอบไม่คำนึงถึงตัวพิมพ์เล็กพิมพ์ใหญ่ ดังนั้นHTTPS://จึงได้รับการยอมรับ - Fix: วาง Gotenberg หลัง TLS และกำหนดค่า endpoint เป็น HTTPS ระบบจะปฏิเสธ HTTP ธรรมดาแม้ในการพัฒนาบนเครื่องท้องถิ่น
URL ไม่ถูกต้อง แยกวิเคราะห์ไม่ได้: “Invalid Gotenberg API URL: unable to parse”
หัวข้อที่มีชื่อว่า “URL ไม่ถูกต้อง แยกวิเคราะห์ไม่ได้: “Invalid Gotenberg API URL: unable to parse””- Trigger: ไม่สามารถแยกวิเคราะห์ URL ให้เป็น scheme และ host ได้
- Fix: ระบุ URL แบบสัมบูรณ์ที่ถูกต้องตามไวยากรณ์ เช่น
https://gotenberg.example.com:3000
URL ต้องไม่ resolve ไปยังที่อยู่ IP แบบ private หรือ reserved: “Gotenberg API URL must not resolve to a private or reserved IP address”
หัวข้อที่มีชื่อว่า “URL ต้องไม่ resolve ไปยังที่อยู่ IP แบบ private หรือ reserved: “Gotenberg API URL must not resolve to a private or reserved IP address””- Trigger: host เป็น Internet Protocol (IP) literal แบบ private หรือ reserved หรือ เป็น hostname ที่ resolve (ผ่านระเบียน A/AAAA ทั้งหมด) ไปยังที่อยู่แบบ private หรือ reserved รายการใดรายการหนึ่ง การทำเช่นนี้จะบล็อกช่วงที่อยู่แบบ private จาก Request for Comments (RFC) 1918 ที่อยู่ loopback และที่อยู่ link-local
- Fix: ชี้ bridge ไปยังที่อยู่สาธารณะที่ routable หรือที่อยู่ของบริการที่แบ่งเซกเมนต์อย่างเหมาะสม หากตั้งใจให้ Gotenberg อยู่บนเครือข่ายส่วนตัว SSRF guard ของ bridge จะปฏิเสธตามการออกแบบ เปิดให้เข้าถึงผ่านที่อยู่ที่ guard ยอมรับ แล้วป้องกันเส้นทางนั้นด้วยการควบคุมเครือข่ายและการพิสูจน์ตัวตน ดู /integrations/gotenberg/security-and-operations/
คำตอบ DNS ของ URL เปลี่ยนไปนับจากการตรวจสอบ อาจเป็นการโจมตีแบบ DNS rebinding: “Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack”
หัวข้อที่มีชื่อว่า “คำตอบ DNS ของ URL เปลี่ยนไปนับจากการตรวจสอบ อาจเป็นการโจมตีแบบ DNS rebinding: “Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack””- Trigger: ระหว่างการตรวจสอบความถูกต้องครั้งแรกกับคำขอ การ resolve Domain Name System (DNS) อีกครั้งส่งคืนที่อยู่ที่ไม่ได้อยู่ในชุดที่ผ่านการตรวจสอบความถูกต้องเดิม
- Fix: นี่คือพฤติกรรมของ guard แบบ time-of-check/time-of-use ตรวจสอบ DNS ของ host สาเหตุที่ไม่ผิดปกติคือ load balancer ที่หมุนเวียนที่อยู่ สาเหตุที่เป็นอันตรายคือการโจมตีแบบ rebinding ใช้ที่อยู่ที่เสถียรหรือชื่อที่มีชุดระเบียนที่เสถียรสำหรับ endpoint ของ Gotenberg
ความล้มเหลวของการตรวจสอบอินพุต
หัวข้อที่มีชื่อว่า “ความล้มเหลวของการตรวจสอบอินพุต”นโยบายความปลอดภัยจะยกความล้มเหลวเหล่านี้ขึ้นก่อนส่งคำขอ แต่ละรายการเป็น RuntimeException ธรรมดา เว้นแต่จะระบุไว้
ไม่พบไฟล์หรืออ่านไฟล์ไม่ได้: “File not found or not readable: ”
หัวข้อที่มีชื่อว่า “ไม่พบไฟล์หรืออ่านไฟล์ไม่ได้: “File not found or not readable: ””- Type:
GotenbergConvertException - Trigger:
convertFile()ไม่สามารถ canonicalize เส้นทางได้ หรือเส้นทางที่ resolve แล้วไม่ใช่ไฟล์ปกติที่อ่านได้ ไดเรกทอรีจะกระตุ้นกรณีนี้เช่นกัน - Fix: ส่งเส้นทางไปยังไฟล์ที่มีอยู่และอ่านได้ เส้นทางจะถูก canonicalize ด้วย
realpath()ก่อน และยังช่วยป้องกันการ traversal ด้วย
ขนาดไฟล์เกินขีดจำกัดสูงสุดที่อนุญาต: “File size ( bytes) exceeds maximum allowed size ( bytes)”
หัวข้อที่มีชื่อว่า “ขนาดไฟล์เกินขีดจำกัดสูงสุดที่อนุญาต: “File size ( bytes) exceeds maximum allowed size ( bytes)””- Trigger: อินพุตมีขนาดใหญ่กว่า
maxFileSize(ค่าเริ่มต้น 52,428,800 ไบต์ = 50 MiB) - Fix: เพิ่ม
maxFileSizeหากเอกสารจำเป็นต้องใช้ขนาดนั้นจริง หรือปฏิเสธการอัปโหลดตั้งแต่ต้นทาง ตั้งค่าเพดานให้ต่ำที่สุดเท่าที่เอกสารจริงของคุณจะอนุญาต นี่คือขีดจำกัดทรัพยากรในตัวเพียงอย่างเดียวของ bridge
การปฏิเสธชื่อไฟล์
หัวข้อที่มีชื่อว่า “การปฏิเสธชื่อไฟล์”bridge จะตรวจสอบความถูกต้องของชื่อไฟล์ สำหรับการแปลงไฟล์ ชื่อไฟล์คือ basename ของเส้นทางที่ resolve แล้ว สำหรับ convertString() คือชื่อที่คุณส่งเข้าไป รายการต่อไปนี้แต่ละรายการเป็น RuntimeException:
| ส่วนของข้อความ | ตัวกระตุ้น |
|---|---|
must not be empty | ชื่อไฟล์ว่าง |
path traversal sequences (..) | ชื่อมี .. |
forward slashes | ชื่อมี / |
backslashes | ชื่อมี \ |
null bytes | ชื่อมีไบต์ NUL |
control characters | ชื่อมีอักขระควบคุม ASCII (0–31) |
- Fix: ส่ง basename ที่สะอาด สำหรับ
convertString()ให้ระบุชื่อธรรมดา เช่นreport.docxระบบใช้ชื่อนี้สำหรับการตรวจหารูปแบบและเป็นชื่อไฟล์อัปโหลดแบบ multipart ไม่ใช่เป็นเส้นทาง
นามสกุลรูปแบบ office ที่ไม่รู้จัก: “Unknown office format extension: ”
หัวข้อที่มีชื่อว่า “นามสกุลรูปแบบ office ที่ไม่รู้จัก: “Unknown office format extension: ””- Type:
ValueError - Trigger: นามสกุลไฟล์ไม่ใช่หนึ่งใน
docx,xlsx,pptx,odt,ods,odp(ไม่คำนึงถึงตัวพิมพ์เล็กพิมพ์ใหญ่ ยอมรับจุดนำหน้าได้) - Fix: แปลงเฉพาะหกรูปแบบที่รู้จักเท่านั้น bridge ไม่รู้จักรูปแบบไบนารีรุ่นเก่า (
.doc,.xls,.ppt),.rtf,.csv, ข้อความล้วน หรือรูปภาพ แปลงอินพุตเหล่านี้ให้เป็นรูปแบบที่รู้จักก่อนเรียก bridge หรือส่งผ่านเส้นทางอื่น
ความล้มเหลวของการรับส่งข้อมูลและการตอบกลับ
หัวข้อที่มีชื่อว่า “ความล้มเหลวของการรับส่งข้อมูลและการตอบกลับ”รายการทั้งหมดนี้เป็น GotenbergConvertException
คำขอ HTTP ล้มเหลว: “Gotenberg HTTP request failed: ”
หัวข้อที่มีชื่อว่า “คำขอ HTTP ล้มเหลว: “Gotenberg HTTP request failed: ””- Trigger: PHP Standard Recommendation 18 (PSR-18) client (หรือ transport แบบ cURL-pinned) ยก exception ขึ้นขณะส่งคำขอ สาเหตุอาจเป็นการปฏิเสธการเชื่อมต่อ การหมดเวลา ความล้มเหลวของ TLS handshake หรือ pin ไม่ตรงกัน
- Exception code: code ของ exception จาก client ชั้นล่าง
- Cause: exception ดั้งเดิมของ PSR-18 client ถูกแนบมาเป็น exception ก่อนหน้า
- Fix: ตรวจสอบสี่เรื่อง: ตรวจสอบว่าบริการเข้าถึงได้ด้วย
isAvailable()ตรวจสอบเส้นทางเครือข่าย ตรวจสอบ TLS chain หากมีการกำหนดค่า pinning ไว้ ตรวจสอบว่า SubjectPublicKeyInfo (SPKI) ปัจจุบันของเซิร์ฟเวอร์ตรงกับ pin ที่กำหนดค่าไว้ pin ที่ไม่ตรงกันหลังการหมุนเวียนใบรับรองเป็นสาเหตุที่พบได้บ่อย ดูขั้นตอนการหมุนเวียนใน /integrations/gotenberg/security-and-operations/
ข้อผิดพลาดของ transport แบบ cURL: “cURL transport error (): ”
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดของ transport แบบ cURL: “cURL transport error (): ””- Trigger:
curl_execของ transport แบบ cURL-pinned ล้มเหลวด้วยหมายเลขข้อผิดพลาด cURL ที่ไม่เป็นศูนย์ หรือส่งคืน body ที่ไม่ใช่สตริง - Fix: หมายเลขข้อผิดพลาด cURL ระบุสาเหตุ (TLS, resolve, timeout, pin) ความล้มเหลวของ pinning จะปรากฏที่นี่เมื่อ
CURLOPT_PINNEDPUBLICKEYปฏิเสธใบรับรอง ยืนยันว่า pin ที่กำหนดค่าไว้และที่อยู่ที่ resolve แล้วเป็นปัจจุบัน
การแปลงล้มเหลวด้วยสถานะ HTTP: “Gotenberg conversion failed with HTTP : ”
หัวข้อที่มีชื่อว่า “การแปลงล้มเหลวด้วยสถานะ HTTP: “Gotenberg conversion failed with HTTP : ””- Trigger: สถานะของการตอบกลับไม่ใช่
200body จะถูกรวมไว้โดยตัดให้เหลือ 500 อักขระแรก พร้อมต่อท้ายด้วยจุดไข่ปลาเมื่อยาวกว่านั้น - Fix: อ่าน body ที่รวมมา ข้อความแสดงข้อผิดพลาดของ Gotenberg อธิบายว่าเหตุใดการแปลงจึงถูกปฏิเสธ ได้แก่ เนื้อหาเอกสารที่ไม่รองรับ ความล้มเหลวภายในของ LibreOffice หรือการปฏิเสธการพิสูจน์ตัวตนด้วย
401หรือ403401/403หมายความว่าapiKeyขาดหายไปหรือไม่ถูกต้อง5xxเป็นความล้มเหลวฝั่งบริการและเป็นกรณีที่เหมาะกับการลองใหม่แบบมีขอบเขต
Content-Type ที่ไม่คาดคิดจาก Gotenberg: “Unexpected Content-Type from Gotenberg: (expected application/pdf)”
หัวข้อที่มีชื่อว่า “Content-Type ที่ไม่คาดคิดจาก Gotenberg: “Unexpected Content-Type from Gotenberg: (expected application/pdf)””- Trigger: สถานะคือ
200แต่Content-Typeของการตอบกลับไม่มีapplication/pdf - Fix: โดยทั่วไปหมายความว่า proxy หรือ gateway ส่งคืนหน้าข้อผิดพลาด HTML หรือหน้า redirect พร้อม
200bridge ตั้งใจปิดการตาม redirect บน transport ที่ pinned ไว้ ดังนั้นการตอบกลับแบบ3xxจึงไม่ถูกตามไปยัง host ที่ไม่ได้ตรวจสอบโดยเงียบๆ body ที่มาถึงพร้อมContent-Typeที่ผิดบ่งชี้ว่ามีบางอย่างระหว่างคุณกับ Gotenberg กำลังแทรกแซง ตรวจสอบเส้นทางเครือข่าย
body ของการตอบกลับไม่ขึ้นต้นด้วย header %PDF ข้อมูล PDF ไม่ถูกต้อง: “Response body does not start with %PDF header — invalid PDF data”
หัวข้อที่มีชื่อว่า “body ของการตอบกลับไม่ขึ้นต้นด้วย header %PDF ข้อมูล PDF ไม่ถูกต้อง: “Response body does not start with %PDF header — invalid PDF data””- Trigger: สถานะ
200Content-Typeยอมรับได้ แต่ body ไม่ขึ้นต้นด้วยลายเซ็น%PDF - Fix: ต้นทางส่งคืนข้อมูลที่ไม่ใช่ไฟล์ Portable Document Format (PDF) แม้จะมี header ให้ถือว่าการตอบกลับไม่น่าเชื่อถือและตรวจสอบบริการ อย่าเขียน body ลงดิสก์ bridge ปฏิเสธที่จะส่งคืนเป็นผลลัพธ์
ความล้มเหลวของการกำหนดค่า pin
หัวข้อที่มีชื่อว่า “ความล้มเหลวของการกำหนดค่า pin”รูปแบบ SPKI pin ไม่ถูกต้อง: “Invalid SPKI pin format: (expected sha256/)”
หัวข้อที่มีชื่อว่า “รูปแบบ SPKI pin ไม่ถูกต้อง: “Invalid SPKI pin format: (expected sha256/)””- Type:
InvalidSpkiPinException - Trigger: สตริง pin ที่กำหนดค่าไว้ไม่ขึ้นต้นด้วย
sha256/หรือsha256// - Fix: จัดรูปแบบ pin แต่ละตัวเป็น
sha256/<base64-encoded-spki-hash>transport ยังยอมรับรูปแบบsha256//<base64>แบบ cURL-native ด้วย สร้างค่าจาก SubjectPublicKeyInfo ของใบรับรองเซิร์ฟเวอร์ ไม่ใช่จากใบรับรองทั้งใบ
ระบบแจ้งว่าไม่พร้อมใช้งานแต่บริการทำงานอยู่: “It says unavailable but the service is up”
หัวข้อที่มีชื่อว่า “ระบบแจ้งว่าไม่พร้อมใช้งานแต่บริการทำงานอยู่: “It says unavailable but the service is up””isAvailable() ส่งคืน false โดยไม่มีการเรียกเครือข่ายใดๆ เมื่อ URL ว่าง ไม่ใช่ HTTPS หรือ resolve ไปยังที่อยู่แบบ private/reserved และยังส่งคืน false เมื่อเกิดข้อผิดพลาดเครือข่ายใดๆ หรือเมื่อ /health ส่งคืน 500 ขึ้นไป ในกรณีเหล่านั้นจะ catch ข้อผิดพลาดแทนการ throw ตรวจสอบตามลำดับนี้:
- URL ที่กำหนดค่าไว้ไม่ว่างและเป็น HTTPS
- host ไม่ resolve ไปยังที่อยู่แบบ private/reserved (SSRF guard ปฏิเสธแม้กระทั่งสำหรับการ probe)
<apiUrl>/healthเข้าถึงได้จาก host ของแอปพลิเคชันและส่งคืนสถานะที่ต่ำกว่า500
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- /integrations/gotenberg/configuration/ — ตัวเลือกทั้งหมดและกฎการเลือก transport
- /integrations/gotenberg/production-usage/ — นโยบายการลองใหม่และสัญญาการจัดการความล้มเหลว
- /integrations/gotenberg/security-and-operations/ — โมเดล SSRF และการหมุนเวียน pin
- /integrations/gotenberg/quickstart/ — ลำดับการ catch ที่ครบถ้วนในบริบท