Puppeteer PDF-部署到 Docker 容器时表头重叠

问题描述 投票:0回答:1

由于某种原因,当我部署此功能时,我无法正确生成这些 PDF。这似乎是 Puppeteer 的问题,因为即使我在 Chrome 中打开 html 并打印为 pdf,我也可以让它正确打印。请参阅下面的 docker 文件、puppeteer 实现和 HTML(由于模板的构建方式,这有点混乱,但您会明白的):

FROM node:20-alpine

RUN apk add --no-cache \
    chromium \
    nss \
    freetype \
    freetype-dev \
    harfbuzz \
    ca-certificates \
    ttf-freefont \
    fontconfig

RUN fc-cache -f -v

# Set environment variable to use Puppeteer with Chromium installed in non-standard location
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
COPY .npmrc ./

# RUN npm install
# If you are building your code for production
RUN npm install pm2 -g
RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 4042

CMD [ "pm2-runtime", "start", "/usr/src/app/process.yml" ]
import { launch } from 'puppeteer';

class FormatDocsApi {
    async formatHtmlString({ htmlString }) {
        const browser = await launch({
            headless: true,
            args: [
                '--disable-features=IsolateOrigins',
                '--disable-site-isolation-trials',
                '--autoplay-policy=user-gesture-required',
                '--disable-background-networking',
                '--disable-background-timer-throttling',
                '--disable-backgrounding-occluded-windows',
                '--disable-breakpad',
                '--disable-client-side-phishing-detection',
                '--disable-component-update',
                '--disable-default-apps',
                '--disable-dev-shm-usage',
                '--disable-domain-reliability',
                '--disable-extensions',
                '--disable-features=AudioServiceOutOfProcess',
                '--disable-hang-monitor',
                '--disable-ipc-flooding-protection',
                '--disable-notifications',
                '--disable-offer-store-unmasked-wallet-cards',
                '--disable-popup-blocking',
                '--disable-print-preview',
                '--disable-prompt-on-repost',
                '--disable-renderer-backgrounding',
                '--disable-setuid-sandbox',
                '--disable-speech-api',
                '--disable-sync',
                '--hide-scrollbars',
                '--ignore-gpu-blacklist',
                '--metrics-recording-only',
                '--mute-audio',
                '--no-default-browser-check',
                '--no-first-run',
                '--no-pings',
                '--no-sandbox',
                '--no-zygote',
                '--password-store=basic',
                '--use-gl=swiftshader',
                '--use-mock-keychain',
            ],
        });
        console.log('Browser launched:', await browser.version());
        const page = await browser.newPage();
        console.log('page created');
        await page.emulateMediaType('print');
        await page.evaluateHandle('document.fonts.ready');
        await page.setContent(htmlString, { waitUntil: 'networkidle0' });
        const pdfOptions = {
            displayHeaderFooter: true,
            preferCSSPageSize: true,
            format: 'A4',
            headerTemplate: '<div></div>',
            footerTemplate:
                "<div style=\"font-size:8px; text-align:end; width:100%; margin:0px 10px 0px 10px;\"><span class='pageNumber'></span> / <span class='totalPages'></span></div>",
            margin: {
                top: '40px',
                bottom: '40px',
                left: '40px',
                right: '40px',
            },
        };
        console.log('PDF buffer generating now...');
        const pdfBuffer = await page.pdf(pdfOptions);
        // Close the browser
        await browser.close();
        return pdfBuffer; // Return a success message or data
    }
}

export { FormatDocsApi };

HTML/CSS

我运行的是node 20,puppeteer v22,浏览器是Chrome/123.0.6312.122。 我已经为此奋斗了数周,并认为将 Node 升级到 20,将 Puppeteer 升级到 v22 会是解决方案,但部署后仍然无法正常工作。

javascript node.js docker pdf puppeteer
1个回答
0
投票

我尝试将给定的大型 html 示例缩小到更易于管理的大小,以便可以轻松复制:

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <style>
         #nss-summary-table-header {
         background-color: lightgrey;
         border-left: 0.1px solid black;
         border-right: 0.1px solid black;
         }
         .nss-summary-table-header {
         background-color: lightgrey;
         border-left: 0.1px solid black;
         border-right: 0.1px solid black;
         page-break-inside: avoid;
         }
         .nss-summary-table {
         border-collapse: collapse;
         width: 100%;
         height: 100%;
         table-layout: fixed;
         padding: 0 !important;
         float: none !important;
         }
         td {
         text-align: center;
         margin: 0 !important;
         height: 100%;
         padding-top: 2px;
         padding-bottom: 2px;
         } 
         th {
         text-align: center;
         margin: 0 !important;
         }
         tr {
         padding: 0 !important;
         margin: 0 !important;
         }
         .nss-summary-table-nested {
         border-collapse: collapse;
         width: 100%;
         height: 100%;
         table-layout: fixed;
         margin: 0 !important;
         padding: 0 !important;
         float: none !important;
         page-break-inside: avoid;
         }
         .nested-table {
         border-collapse: collapse;
         width: 100%;
         height: 100%;
         table-layout: fixed;
         margin: 0 !important;
         padding: 0 !important;
         float: none !important;
         page-break-inside: avoid;
         }
         .nss-summary-totals {
         width: 100%;
         display: table;
         border-collapse: collapse;
         }
         .nss-summary-totals td {
         padding-top: 4px;
         padding-bottom: 4px;
         }
         #nss-total-row div {
         text-align: left;
         background-color: white;
         margin: 2px;
         }
         #nss-total-row-wrapper {
         display: flex;
         justify-content: flex-end;
         width: 100%;
         margin-top: 10px;
         }
         #nss-disclaimer {
         font-style: italic;
         margin-bottom: 10px;
         page-break-after: always;
         }
         .nss-text-align-right {
         text-align: right !important;
         }
         .text-align-justify {
         text-align: justify;
         }
         .nss-border-left-none {
         border-left: none !important;
         }
         .nss-bold {
         font-weight: bold;
         }
         .nss-col-20-percent-w {
         width: 20%;
         } 
         .nss-col-25-percent-w {
         width: 25%;
         }
         .parent-td {
         width: 80%;
         }
         .border-left-none {
         border-left: none !important;
         }
      </style>
      <style>
         html {
         -webkit-print-color-adjust: exact;
         }
         body {
         font-family: Arial, sans-serif;
         font-size: .7rem;
         padding: 40px;
         height: 100%;
         page-break-inside: avoid;
         }
         hr {
         border-style: solid;
         border-bottom: 2px solid black;
         }
         hr.hr-bold {
         border-bottom: 4px solid black;
         }
         h1 {
         text-transform: uppercase;
         }
      </style>
      <title></title>
   </head>
   <body>
      <div style="height: 800px">
      </div>
      <div id="name-search-summary">
         <br>
         <table class="nss-summary-table" style="border-top: 0.1px solid black;">
            <thead id="nss-summary-table-header" class="nss-summary-table-header">
               <tr>
                  <th class="nss-bold" colspan="5" style="background-color: #70A6AD; color: #ffffff; padding: 4px 1px; border-bottom: 0.1px solid black;">Client, Test </th>
               </tr>
               <tr>
                  <th class="nss-bold">Jurisdiction</th>
                  <th class="nss-bold">Service</th>
                  <th class="nss-bold">Results</th>
                  <th class="nss-bold">Through Date</th>
                  <th class="nss-bold">Fees</th>
               </tr>
            </thead>
            <tbody>
               <tr style="">
                  <td colspan="5" style="padding: 0 !important; margin: 0 !important;">
                     <table class="nss-summary-table-nested content-block is-first" style="border: 0.1px solid black;">
                        <tbody>
                           <tr style="border-bottom: 0.1px solid black;">
                              <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px; border-right: 0.1px solid black;">Recorder, Denver, CO</td>
                              <td colspan="4" class="parent-td" style="padding: 0 !important; margin: 0 !important;">
                                 <table class="nested-table" style="">
                                    <tbody>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">Federal Tax Lien Search</td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                          <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px;">$80.00</td>
                                       </tr>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">State Tax Lien Search</td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                       </tr>
                                    </tbody>
                                 </table>
                              </td>
                           </tr>
                        </tbody>
                     </table>
                     <table class="nss-summary-table-nested content-block " style="border: 0.1px solid black;">
                        <tbody>
                           <tr style="border-bottom: 0.1px solid black;">
                              <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px; border-right: 0.1px solid black;">District Court, Big Stone, MN</td>
                              <td colspan="4" class="parent-td" style="padding: 0 !important; margin: 0 !important;">
                                 <table class="nested-table" style="">
                                    <tbody>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">Civil Search - Pending Only</td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                          <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px;">$40.00</td>
                                       </tr>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">Judgment Search</td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                       </tr>
                                    </tbody>
                                 </table>
                              </td>
                           </tr>
                        </tbody>
                     </table>
                     <table class="nss-summary-table-nested content-block " style="border: 0.1px solid black;">
                        <tbody>
                           <tr style="border-bottom: 0.1px solid black;">
                              <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px; border-right: 0.1px solid black;">U.S. District Court, Minnesota District</td>
                              <td colspan="4" class="parent-td" style="padding: 0 !important; margin: 0 !important;">
                                 <table class="nested-table" style="">
                                    <tbody>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">Civil Search - Pending Only</td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                          <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px;">$40.00</td>
                                       </tr>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">Judgment Search</td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                       </tr>
                                    </tbody>
                                 </table>
                              </td>
                           </tr>
                        </tbody>
                     </table>
                     <table class="nss-summary-table-nested content-block " style="border: 0.1px solid black;">
                        <tbody>
                           <tr style="border-bottom: 0.1px solid black;">
                              <td rowspan="1" class="nss-col-20-percent-w" style="padding: 4px 1px; border-right: 0.1px solid black;">U.S. Bankruptcy Court, Minnesota Division</td>
                              <td colspan="4" class="parent-td" style="padding: 0 !important; margin: 0 !important;">
                                 <table class="nested-table" style="">
                                    <tbody>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">Bankruptcy Search</td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                          <td rowspan="1" class="nss-col-20-percent-w" style="padding: 4px 1px;">$20.00</td>
                                       </tr>
                                    </tbody>
                                 </table>
                              </td>
                           </tr>
                        </tbody>
                     </table>
                  </td>
               </tr>
            </tbody>
         </table>
         <table class="nss-summary-table" style="border-top: 0.1px solid black;">
            <thead id="nss-summary-table-header" class="nss-summary-table-header">
               <tr>
                  <th class="nss-bold" colspan="5" style="background-color: #70A6AD; color: #ffffff; padding: 4px 1px; border-bottom: 0.1px solid black;">Person, Christofer </th>
               </tr>
               <tr>
                  <th class="nss-bold">Jurisdiction</th>
                  <th class="nss-bold">Service</th>
                  <th class="nss-bold">Results</th>
                  <th class="nss-bold">Through Date</th>
                  <th class="nss-bold">Fees</th>
               </tr>
            </thead>
            <tbody>
               <tr style="">
                  <td colspan="5" style="padding: 0 !important; margin: 0 !important;">
                     <table class="nss-summary-table-nested content-block is-first" style="border: 0.1px solid black;">
                        <tbody>
                           <tr style="border-bottom: 0.1px solid black;">
                              <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px; border-right: 0.1px solid black;">Recorder, Denver, CO</td>
                              <td colspan="4" class="parent-td" style="padding: 0 !important; margin: 0 !important;">
                                 <table class="nested-table" style="">
                                    <tbody>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">Federal Tax Lien Search</td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style="border-bottom: 0.1px solid black; padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                          <td rowspan="2" class="nss-col-20-percent-w" style="padding: 4px 1px;">$80.00</td>
                                       </tr>
                                       <tr style="">
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">State Tax Lien Search</td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">
                                             None Found
                                          </td>
                                          <td class="nss-col-20-percent-w" style=" padding: 4px 1px; border-right: 0.1px solid black;">2/12/2024</td>
                                       </tr>
                                    </tbody>
                                 </table>
                              </td>
                           </tr>
                        </tbody>
                     </table>
                  </td>
               </tr>
            </tbody>
         </table>
      </div>
   </body>
</html>

我的观察是,pdf 打印仅显示 docker 内部的问题。需要注意的是,docker内部安装了chromium的alpine linux版本。对我来说是:

Chromium 123.0.6312.122 Alpine Linux

在我的 MacOS 上是:

Chrome/123.0.6312.122

我使用 vscode 进入运行 docker 容器,并且能够在没有 puppeteer 的情况下使用命令行复制相同的行为

/usr/bin/chromium-browser --headless --disable-gpu --no-sandbox --print-to-pdf ./test.html
假设 html 在同一目录中保存为 

test.html

。这会生成 
output.pdf
,我们可以更轻松地测试行为。

更多观察:

    仅当第一个表转到下一页,然后在与第二个表合并后立即转到下一页时,才会出现此问题
  • 您可以降低第一个 div 的高度:
  • <div style="height: 800px"></div>
    。如果您将其减少到足以将所有内容放入单页中(例如使用 
    height: 100px
    ),则不会出现问题。
我的猜测是,这是 chromium 的 alpine 版本中的错误,而不是 puppeteer/nodejs/docker 中的错误。这是到目前为止我能找到的关于这个问题的全部内容。

© www.soinside.com 2019 - 2024. All rights reserved.