Headless Chrome зависает при попытке распечатать страницу в формате PDF

Headless Chrome зависает при попытке распечатать страницу в формате PDF

В нашей организации мы используем 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

Нам не удалось получить никаких полезных журналов от headless-экземпляров Chrome, хотя мы выполнили все необходимые шаги, указанные здесь:https://www.chromium.org/for-testers/enable-logging Мы попытались отладить эти headless-экземпляры с помощью опции --remote-debugging-port, но не нашли ничего подозрительного в консоли или где-либо еще. Страница, похоже, была успешно загружена, и похоже, что Chrome просто отказался печатать страницы.

У кого-то были похожие проблемы? Или, может быть, у кого-то есть идеи, почему это происходит? Может быть, у кого-то есть советы, как включить ведение журнала на headless-экземплярах Chrome? Мы будем благодарны за любую помощь.

Вот версии приложений:

Google Chrome: 76.0.3809.100
chrome-devtools-java-client: 1.3.5

Спасибо! Макс.

решение1

Эта проблема вызвана базовой реализацией API вебсокета, Tyrus. Она имеетмаксимальный размер сообщения по умолчанию 4 МБ. Этот URL и многие другие (особенно если вы включите печать фонов) приводят к PDF-файлам, которые (при кодировании в base 64) превышают этот предел в 4 МБ. В этом случае веб-сокет закрывается с помощьюОшибка переполнения буфера, однако мы не видим этого какchrome-devtools-java-client onCloseне прослушивает события вебсокета.

Эту проблему можно решить, передав результат печати в потоковом режиме...

Передайте PrintToPDFTransferMode.RETURN_AS_STREAMв качестве transferModeпараметра Page.printToPdfи затем считывайте из потока с буфером, значительно меньшим, чем ограничение в 4 МБ (даже после увеличения из-за base 64). Я использую 1 МБ:

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, но не думаю, что мы увидим это при печати!

Связанный контент