在我们的组织中,我们使用 headless-chrome 将网页转换为 PDF。我们有一个专门的 Java 应用程序,它使用以下 CDT 客户端启动 chrome 实例并与它们通信:https://github.com/kklisura/chrome-devtools-java-client 在大多数情况下,一切都按预期进行,我们得到了 PDF,但对于某些网页,headless-chrome 在 PDF 打印步骤期间会挂起。此类页面的示例:
https://www.idc.com/cee/events/64662-web-developers-event-for-automatic-tests-on-idc-com-do-not-update-manually/print-agenda
尽管我们遵循了此处指定的所有必要步骤,但我们无法从无头的 chrome 实例中获取任何有用的日志:https://www.chromium.org/for-testers/enable-logging 我们尝试使用 --remote-debugging-port 选项调试这些无头实例,但在控制台或其他地方没有发现任何可疑的东西。页面似乎已成功加载,但 chrome 似乎只是拒绝打印页面。
其他人有类似的问题吗?或者有人知道为什么会发生这种情况?也许有人有一些关于如何在 Chrome 的无头实例上启用日志记录的提示?我们将不胜感激任何帮助。
以下是应用程序的版本:
Google Chrome: 76.0.3809.100
chrome-devtools-java-client: 1.3.5
谢谢!马克斯。
答案1
此问题是由底层 websocket API 实现 Tyrus 引起的。它有一个默认最大邮件大小为 4MB。此 URL 和许多其他 URL(尤其是启用打印背景时)会导致 PDF(以 base 64 编码时)大于 4MB 限制。在这种情况下,websocket 会以缓冲区溢出错误但我们并不认为chrome-devtools-java-client
不监听 websocketonClose
事件。
您可以通过流式传输打印结果来解决此问题......
将PrintToPDFTransferMode.RETURN_AS_STREAM
作为transferMode
参数传递给Page.printToPdf
,然后使用明显小于 4MB 限制的缓冲区从流中读取(即使在由于 base 64 而增加之后)。我使用 1MB:
private static final int READ_BUFFER_SIZE = 1048576;
final PrintToPDF printToPDF = page.printToPDF(..., PrintToPDFTransferMode.RETURN_AS_STREAM);
final IO io = devToolsService.getIO();
int offset = 0;
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
do {
final Read read = io.read(printToPDF.getStream(), offset, READ_BUFFER_SIZE);
if (read.getBase64Encoded() == Boolean.TRUE) {
byte[] decode = Base64.getDecoder().decode(read.getData());
offset += decode.length;
fos.write(decode);
} else {
byte[] decode = read.getData().getBytes(StandardCharsets.UTF_8);
offset += decode.length;
fos.write(decode);
}
if (read.getEof() == Boolean.TRUE) {
break;
}
} while (true);
}
io.close(printToPDF.getStream());
我不确定offset
结果不是 Base 64 编码的情况下该如何处理,但我认为在打印时我们不会看到这种情况!