生产环境中的 NextPDF Gotenberg
这个桥接器执行的是一次同步 HTTP 往返,并在外层包裹验证逻辑。它不会重试、排队、缓存,也不会限流。这些行为应由桥接器外围的应用程序负责。本页说明这些行为各自应该放在哪里,以及桥接器提供哪些保证,帮助你正确构建其余部分。
请把每一次转换都视为对某个服务发起的远程调用:这个服务由你运营,但并不在你的进程内受你掌控。设计时要考虑它的延迟与失败。
获取配置与机密
标题为“获取配置与机密”的章节GotenbergConfig 保存 API URL,并在启用验证时保存一组 bearer token。token 字段标注了 #[\SensitiveParameter],因此会在堆栈跟踪中被屏蔽。但它的来源仍由你负责。
- 在进程启动时,从你的机密管理器或注入的环境值获取 token。不要把它提交到版本控制,也不要放进随镜像一起发布的配置文件。
- 每个请求范围或每个 worker 只创建一次配置,而不是每次转换都创建。它是不可变的,持有成本也很低。
GotenbergConfig::fromArray()在设计上允许格式不正确的输入:它会静默地用默认值替代。生产环境中,调用fromArray()之前,请自行验证来源数组。这样一来,缺失 URL 会在你的启动流程中以配置错误的形式暴露,而不会等到之后每次转换时才抛出Invalid Gotenberg configuration: apiUrl is empty异常。
timeout(单位为秒,默认 30)是硬性传输超时,由锁定 cURL 的传输层应用。通过 LibreOffice 进行的 Office 转换并非瞬间完成;大型或复杂的文件需要更长时间。请根据真实文件实测出的转换延迟来设置超时,并保留一些余量。请让它低于任何上游网关或 PHP 的 max_execution_time。这样会由桥接器先超时,你得到的是带类型的异常,而不是被强制终止的进程。
如果你依赖注入的 PSR-18 客户端路径(未注入 responseFactory,或使用无 pin 的纯 IP URL),桥接器并不会把 timeout 值应用到该客户端上。也请在 PSR-18 客户端本身设置超时,让两条传输路径都有上限。
桥接器每次调用只发出一次请求,并且绝不重试。请在调用方加入重试逻辑,并确保其安全:
- 只在传输层失败(成因为 PSR-18 客户端异常的
GotenbergConvertException)以及具有幂等性的服务器错误(HTTP502、503、504)时才重试。不要不加区分地对每一个GotenbergConvertException都重试。400类响应通常代表输入有误,重试也会以同样的方式失败。 - 请使用带有抖动(jitter)且设有上限的指数退避。负载过重的转换服务会返回
503;持续冲击它只会让停机更严重。 - 为总尝试次数与总挂钟时间设置上限。转换本来就慢,因此无上限的重试会让尾端延迟倍增。
- 重新验证会自动进行:每一次重试调用都会重新执行 URL 验证与地址重新检查,因此重试无法意外绕过 SSRF 防护。
并发与容量
标题为“并发与容量”的章节请求进行期间,每一次转换都会在 Gotenberg 端占用一条连接与一个 LibreOffice worker。桥接器本身是无状态的,可安全地让多个 worker 并发使用。然而,Gotenberg 服务的转换容量是有限的。
- 请从你这一端(通过队列、信号量或 worker 池)限制进行中的转换数量,使其不超过 Gotenberg 能承受的容量。容量规划取决于你的 Gotenberg 部署,而不是本软件包;请参见 /integrations/gotenberg/security-and-operations/.
- 输入大小上限(
maxFileSize,默认 50 MiB)是桥接器唯一内置的资源上限。它会在请求发出之前于进程内强制执行,因此过大的文件绝不会消耗服务容量。请将它调低到满足真实文件需求的程度;较小的上限比更大的上限更适合作为低成本的拒绝服务防护手段。 - 这里没有进程内缓存。如果同一份文件会被反复转换,请在你的应用程序中以输入内容的哈希值为键,缓存生成的 PDF。
可观测性
标题为“可观测性”的章节注入一个 PSR-3 日志记录器,即可在每次转换请求时获得一条 debug 日志。该日志包含请求 URL、文件名、检测到的格式,以及请求内容长度。它不会包含文件内容或 bearer token。
- 将该信号提升为指标:按格式与结果统计转换次数,并把每次
convertFile()/convertString()调用前后的挂钟时间记录为延迟直方图。桥接器本身并不发出指标。 - 结果对象会暴露一个
renderTimeMs字段,除非你的集成自行测量并设置它,否则它会是0.0;桥接器并不会从 Gotenberg 的响应填入它。如果你需要这个数字,请自行对该调用计时。 - 记录异常时,请同时记录其类型。异常类型是判断失败位置的主要信号;完整清单收录于 /integrations/gotenberg/troubleshooting/.
- 请从你的就绪(readiness)或健康(health)端点探测
isAvailable(),而不是在每次转换时探测。它是一个发往/health的HEAD请求。在每次转换前都执行它,只会让你对该服务的请求速率倍增,却毫无益处。
失败处理约定
标题为“失败处理约定”的章节桥接器会以带类型的异常呈现失败,并且绝不返回不完整或未经验证的结果。相关保证如下:
- 非
200的状态码、Content-Type不含application/pdf,或内容开头不是%PDF,都会分别引发GotenbergConvertException。只有在这三项检查全部通过时,才会返回结果对象。 - PSR-18 客户端的失败(包括网络失败或超时)会被包装为
GotenbergConvertException,以原始异常作为其成因,并以客户端的代码作为异常代码。 - 验证失败(非 HTTPS 的 URL、private/reserved 地址、过大的输入、不安全的文件名)会在产生任何网络流量之前引发
RuntimeException。 - 无法识别的扩展名会在产生任何网络流量之前引发
ValueError。
请捕获这些具体类型。examples/convert-office-to-pdf.php 中的示例程序展示了完整的捕获顺序。/integrations/gotenberg/troubleshooting/ 说明了每一个触发情境。
后处理的边界
标题为“后处理的边界”的章节桥接器生成一份 PDF 之后就停止。一个常见的生产流程是:
- 使用这个桥接器转换 Office 文件。
- 将生成的字节载入一份 NextPDF 文件。
- 应用后处理——页面组装、水印、PDF/A 转换、数字签名。
第 3 步是 NextPDF 的职责,而不是桥接器的。签名、PDF/A profile 与水印由 nextpdf/premium 提供。请将转换与后处理保持为相互独立的阶段,这样转换失败与签名失败便能分别诊断。
Pro 版的 PAdES 支持仅限于 B-B 基准。它并不提供 B-T、B-LT 或 B-LTA,而且这些 profile 并不会因为通过这个桥接器转换文件而被隐含包含。长期验证能力属于另一个版本层级的议题,并不在本软件包的范围之内。
另请参阅
标题为“另请参阅”的章节- /integrations/gotenberg/configuration/ — 传输选择规则与 pin 模型。
- /integrations/gotenberg/security-and-operations/ — 部署并加固 Gotenberg 依赖包。
- /integrations/gotenberg/troubleshooting/ — 异常清单。
- /integrations/gotenberg/integration/ — 将转换后的 PDF 接入 NextPDF 流程。