Bỏ qua để đến nội dung

Khắc phục sự cố với NextPDF Gotenberg

Bridge báo lỗi rõ ràng và từ sớm. Mỗi lỗi đều phát sinh một exception có kiểu rõ ràng, kèm thông báo nêu đúng nguyên nhân. Hãy dùng trang này như một danh mục tra cứu. Với mỗi lỗi, bạn sẽ có kiểu exception, đoạn thông báo sẽ thấy, điểm phát sinh chính xác trong code path và cách khắc phục.

Các họ exception là:

  • GotenbergConvertException — lỗi ở tầng chuyển đổi (cấu hình, truyền tải hoặc phản hồi).
  • RuntimeException — lỗi ở tầng kiểm tra tính hợp lệ do chính sách bảo mật phát sinh trước khi có bất kỳ lưu lượng mạng nào.
  • ValueError — phần mở rộng tệp không được nhận dạng.
  • InvalidSpkiPinException — chuỗi pin SubjectPublicKeyInfo (SPKI) của Transport Layer Security (TLS) bị sai định dạng.

”Invalid Gotenberg configuration: apiUrl is empty”

Phần tiêu đề “”Invalid Gotenberg configuration: apiUrl is empty””
  • Type: GotenbergConvertException
  • Trigger: Bạn đã gọi convertFile() hoặc convertString() trong khi GotenbergConfig::isValid() là false. Trường hợp này xảy ra khi apiUrl là chuỗi rỗng.
  • Fix: Cung cấp một URL HTTPS không rỗng. Nếu bạn dựng cấu hình bằng fromArray(), lưu ý rằng nó âm thầm thay '' cho một api_url bị thiếu hoặc không phải chuỗi. Hãy kiểm tra tính hợp lệ của nguồn cấu hình trong lúc khởi động.

Những lỗi này đến từ chính sách bảo mật, vốn bảo vệ khỏi tấn công giả mạo yêu cầu từ phía máy chủ (SSRF). Bridge phát sinh chúng trước khi gửi bất kỳ yêu cầu nào. Mỗi lỗi là một RuntimeException thông thường.

”Gotenberg API URL must use HTTPS (got: http)”

Phần tiêu đề “”Gotenberg API URL must use HTTPS (got: http)””
  • Trigger: Lược đồ URL được cấu hình không phải là https. Phép kiểm tra không phân biệt chữ hoa chữ thường, nên HTTPS:// vẫn được chấp nhận.
  • Fix: Đặt Gotenberg phía sau TLS và cấu hình endpoint HTTPS. HTTP thuần sẽ bị từ chối ngay cả khi phát triển cục bộ.
  • Trigger: Không thể phân tích URL thành lược đồ và máy chủ.
  • Fix: Cung cấp một URL tuyệt đối hợp lệ về cú pháp, ví dụ https://gotenberg.example.com:3000.

”URL phân giải về địa chỉ IP riêng tư hoặc dành riêng — “Gotenberg API URL must not resolve to a private or reserved IP address””

Phần tiêu đề “”URL phân giải về địa chỉ IP riêng tư hoặc dành riêng — “Gotenberg API URL must not resolve to a private or reserved IP address”””
  • Trigger: Máy chủ là một địa chỉ Internet Protocol (IP) riêng tư hoặc dành riêng dạng literal, hoặc một tên máy chủ phân giải (qua tất cả các bản ghi A/AAAA) đến bất kỳ địa chỉ riêng tư hoặc dành riêng nào. Điều này chặn các dải địa chỉ riêng tư từ Request for Comments (RFC) 1918, loopback và link-local.
  • Fix: Hướng bridge đến một địa chỉ công khai có thể định tuyến hoặc một địa chỉ dịch vụ được phân đoạn đúng cách. Nếu bạn chủ ý đặt Gotenberg trên mạng riêng, bộ bảo vệ SSRF của bridge sẽ từ chối theo thiết kế. Hãy đưa nó ra ngoài qua một địa chỉ mà bộ bảo vệ chấp nhận, rồi bảo vệ đường dẫn đó bằng các biện pháp kiểm soát mạng và xác thực. Xem /integrations/gotenberg/security-and-operations/.

”Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack”

Phần tiêu đề “”Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack””
  • Trigger: Giữa lần kiểm tra tính hợp lệ ban đầu và yêu cầu, một lần phân giải Domain Name System (DNS) mới đã trả về một địa chỉ không nằm trong tập đã được kiểm tra ban đầu.
  • Fix: Đây là lúc bộ bảo vệ time-of-check/time-of-use kích hoạt. Hãy điều tra DNS của máy chủ. Một nguyên nhân hợp lệ là bộ cân bằng tải xoay vòng các địa chỉ. Một nguyên nhân độc hại là tấn công rebinding. Hãy dùng một địa chỉ ổn định hoặc một tên có tập bản ghi ổn định cho endpoint Gotenberg.

Chính sách bảo mật phát sinh các lỗi này trước khi gửi yêu cầu. Mỗi lỗi là một RuntimeException thông thường, trừ khi có ghi chú khác.

”Không tìm thấy hoặc không đọc được tệp — “File not found or not readable: ””

Phần tiêu đề “”Không tìm thấy hoặc không đọc được tệp — “File not found or not readable: ”””
  • Type: GotenbergConvertException
  • Trigger: convertFile() không thể chuẩn hóa đường dẫn, hoặc đường dẫn đã phân giải không phải là một tệp thông thường có thể đọc được. Thư mục cũng sẽ kích hoạt lỗi này.
  • Fix: Truyền vào đường dẫn đến một tệp đang tồn tại và có thể đọc được. Đường dẫn được chuẩn hóa trước bằng realpath(), nhờ đó traversal cũng bị vô hiệu hóa.

”File size ( bytes) exceeds maximum allowed size ( bytes)”

Phần tiêu đề “”File size ( bytes) exceeds maximum allowed size ( bytes)””
  • Trigger: Đầu vào lớn hơn maxFileSize (mặc định 52.428.800 byte = 50 MiB).
  • Fix: Tăng maxFileSize nếu tài liệu thực sự cần, hoặc từ chối tệp tải lên ở tầng phía trên. Hãy giữ giới hạn ở mức thấp nhất mà tài liệu thực tế của bạn cho phép. Đây là giới hạn tài nguyên tích hợp sẵn duy nhất của bridge.

Bridge kiểm tra tính hợp lệ của tên tệp. Với chuyển đổi tệp, tên tệp là basename của đường dẫn đã phân giải; với convertString(), đó là tên bạn truyền vào. Mỗi trường hợp dưới đây là một RuntimeException:

Đoạn thông báoNguyên nhân kích hoạt
must not be emptytên tệp rỗng
path traversal sequences (..)tên có chứa ..
forward slashestên có chứa /
backslashestên có chứa \
null bytestên có chứa một byte NUL
control characterstên có chứa một ký tự điều khiển ASCII (0–31)
  • Fix: Truyền vào một basename sạch. Với convertString(), hãy cung cấp một tên đơn giản chẳng hạn report.docx. Tên này được dùng để phát hiện định dạng và làm tên tệp tải lên multipart, không phải làm đường dẫn.
  • Type: ValueError
  • Trigger: Phần mở rộng tệp không phải là một trong docx, xlsx, pptx, odt, ods, odp (không phân biệt chữ hoa chữ thường, cho phép có dấu chấm ở đầu).
  • Fix: Chỉ chuyển đổi sáu định dạng được nhận dạng. Bridge không nhận dạng các định dạng nhị phân cũ (.doc, .xls, .ppt), .rtf, .csv, văn bản thuần hoặc hình ảnh. Hãy chuyển đổi các đầu vào này sang một định dạng được nhận dạng trước khi gọi bridge, hoặc định tuyến chúng qua một đường dẫn khác.

Tất cả những lỗi này đều là GotenbergConvertException.

  • Trigger: PHP Standard Recommendation 18 (PSR-18) client (hoặc transport được pin bằng cURL) đã phát sinh một exception trong khi gửi yêu cầu. Nguyên nhân có thể là kết nối bị từ chối, hết thời gian chờ, lỗi bắt tay TLS hoặc pin không khớp.
  • Exception code: mã của exception client cơ sở.
  • Cause: exception PSR-18 client gốc được đính kèm làm previous exception.
  • Fix: Kiểm tra bốn điều. Kiểm tra khả năng tiếp cận dịch vụ bằng isAvailable(). Kiểm tra đường dẫn mạng. Kiểm tra chuỗi TLS. Nếu đã cấu hình pinning, hãy kiểm tra rằng SubjectPublicKeyInfo (SPKI) hiện tại của máy chủ khớp với một pin đã cấu hình. Pin không khớp sau khi xoay vòng chứng chỉ là nguyên nhân thường gặp. Xem quy trình xoay vòng tại /integrations/gotenberg/security-and-operations/.
  • Trigger: curl_exec của transport được pin bằng cURL thất bại với số lỗi cURL khác không, hoặc trả về một body không phải chuỗi.
  • Fix: Số lỗi cURL cho biết nguyên nhân (TLS, phân giải, hết thời gian chờ, pin). Lỗi pinning xuất hiện ở đây khi CURLOPT_PINNEDPUBLICKEY từ chối chứng chỉ. Hãy xác nhận rằng các pin đã cấu hình và địa chỉ đã phân giải vẫn còn hiện hành.
  • Trigger: Trạng thái phản hồi không phải là 200. Body được đính kèm, bị cắt còn 500 ký tự đầu tiên, kèm dấu ba chấm khi dài hơn.
  • Fix: Đọc body được đính kèm. Thông báo lỗi của Gotenberg giải thích lý do chuyển đổi bị từ chối: nội dung tài liệu không được hỗ trợ, lỗi nội bộ của LibreOffice, hoặc bị từ chối xác thực với 401 hoặc 403. Một 401/403 nghĩa là apiKey bị thiếu hoặc sai. Một 5xx là lỗi phía dịch vụ và là ứng viên cho một lần thử lại có giới hạn.

”Unexpected Content-Type from Gotenberg: (expected application/pdf)”

Phần tiêu đề “”Unexpected Content-Type from Gotenberg: (expected application/pdf)””
  • Trigger: Trạng thái là 200, nhưng Content-Type của phản hồi không chứa application/pdf.
  • Fix: Điều này thường nghĩa là một proxy hoặc gateway đã trả về trang lỗi HTML hoặc trang chuyển hướng kèm 200. Bridge cố ý vô hiệu hóa việc theo chuyển hướng trên transport được pin, nên phản hồi 3xx không bị âm thầm theo đến một máy chủ chưa được kiểm chứng. Body đi kèm Content-Type sai là dấu hiệu có thứ gì đó giữa bạn và Gotenberg đang can thiệp. Hãy kiểm tra đường dẫn mạng.

”Body phản hồi không bắt đầu bằng header %PDF — “Response body does not start with %PDF header — invalid PDF data””

Phần tiêu đề “”Body phản hồi không bắt đầu bằng header %PDF — “Response body does not start with %PDF header — invalid PDF data”””
  • Trigger: Trạng thái 200, Content-Type chấp nhận được, nhưng body không bắt đầu bằng chữ ký %PDF.
  • Fix: Bên cung cấp đã trả về thứ gì đó không phải là một tệp Portable Document Format (PDF), bất chấp các header. Hãy coi phản hồi là không đáng tin và điều tra dịch vụ. Không ghi body ra đĩa. Bridge từ chối trả nó về làm kết quả.
  • Type: InvalidSpkiPinException
  • Trigger: Một chuỗi pin đã cấu hình không bắt đầu bằng sha256/ hoặc sha256//.
  • Fix: Định dạng mỗi pin thành sha256/<base64-encoded-spki-hash>. Transport cũng chấp nhận dạng sha256//<base64> gốc của cURL. Hãy tạo giá trị từ SubjectPublicKeyInfo của chứng chỉ máy chủ, không phải từ toàn bộ chứng chỉ.

”Báo không khả dụng nhưng dịch vụ vẫn đang hoạt động”

Phần tiêu đề “”Báo không khả dụng nhưng dịch vụ vẫn đang hoạt động””

isAvailable() trả về false mà không thực hiện lệnh gọi mạng nào khi URL rỗng, không phải HTTPS, hoặc phân giải thành một địa chỉ private/reserved. Nó cũng trả về false khi có bất kỳ lỗi mạng nào, hoặc khi /health trả về 500 trở lên; trong những trường hợp đó, nó bắt lỗi thay vì ném ra. Hãy kiểm tra theo thứ tự:

  1. URL đã cấu hình không rỗng và là HTTPS.
  2. Máy chủ không phân giải thành một địa chỉ private/reserved (bộ bảo vệ SSRF từ chối nó ngay cả khi thăm dò).
  3. <apiUrl>/health tiếp cận được từ máy chủ ứng dụng và trả về một trạng thái dưới 500.
  • /integrations/gotenberg/configuration/ — tất cả tùy chọn và quy tắc chọn transport.
  • /integrations/gotenberg/production-usage/ — chính sách thử lại và hợp đồng xử lý lỗi.
  • /integrations/gotenberg/security-and-operations/ — mô hình SSRF và xoay vòng pin.
  • /integrations/gotenberg/quickstart/ — thứ tự bắt lỗi đầy đủ trong ngữ cảnh.