最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Docker平臺(tái)下NodeJs?Puppeteer實(shí)現(xiàn)html轉(zhuǎn)pdf過程示例

 更新時(shí)間:2023年12月21日 14:03:10   作者:強(qiáng)子  
這篇文章主要為大家介紹了Docker平臺(tái)下NodeJs?Puppeteer實(shí)現(xiàn)html轉(zhuǎn)pdf過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Docker 平臺(tái) NodeJs Puppeteer實(shí)現(xiàn)html轉(zhuǎn)pdf

1. 背景

PDM系統(tǒng)中有需求工藝單需要打印成PDF(客戶對(duì)細(xì)節(jié)要求極高),當(dāng)時(shí)出了5個(gè)方案:

  • 從DOM制作屏幕截圖 html2canvas jspdf 文字無(wú)法拷貝
  • 使用PDF庫(kù) jsPDF 或 PDFKit 按組件一個(gè)一個(gè)拼湊,不合適已有html的打印模板方式
  • CSS打印規(guī)則,調(diào)用瀏覽器打印,pdf 文件導(dǎo)入到系統(tǒng),操作繁瑣
  • itext (目前用的) 和spire功能強(qiáng)大,但商業(yè)用途需收費(fèi),wkhtmltopdf開源免費(fèi),后端生成,黑匣子,后端開發(fā)前端代碼,可視化麻煩通過模板生成PDF的實(shí)際效果和模板效果相差較大,修改起來(lái)不好把握
  • 基于Node.js的Puppeteer和HeadlessChrome 展示效果與實(shí)際生成的PDF接近

使用方案5是可以借助puppeteer調(diào)用headless瀏覽器生成PDF,對(duì)css的支持度很高,PDF能很大限度反應(yīng)模板的樣式(對(duì)css支持度很高),前端對(duì)模板的控制度更高,支持dom操作,以下是模板樣式和PDF樣式對(duì)比:

生成的pdf文件樣式和編寫的html模板樣式一致度較高,可以讓前端編寫模板文件實(shí)時(shí)查看html內(nèi)容樣式,改完之后用該模板調(diào)用后端的node服務(wù)生成的pdf模板能較高程度的還原模板內(nèi)容,前端可以通過模板引擎如EJS(類似于當(dāng)前方案后端技術(shù)的freemarker模板)生成模板執(zhí)行一些復(fù)雜的dom操作和樣式控制。

2. 所需依賴

npm install express jsdom puppeteer

express: 用來(lái)和業(yè)務(wù)系統(tǒng)通信,返回pdf流給業(yè)務(wù)系統(tǒng)

jsdom: 解析DOM,在生成pdf的時(shí)候要讓前端可以自定義pdf的頁(yè)頭頁(yè)尾

puppeteer: 調(diào)用headless生成PDF

3. 核心代碼

genPdfFile.js

const puppeteer = require('puppeteer');
const fs = require('fs');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
let browserInstance;
async function getBrowserInstance() {
    if (!browserInstance) {
        browserInstance = await puppeteer.launch({
            headless: true,
            args: ['--no-sandbox', '--disable-setuid-sandbox']
        });
    }
    return browserInstance;
}
async function generatePDFFromHTML(htmlString) {
    try {
            // 啟動(dòng)Puppeteer
    const browser = await getBrowserInstance();
    const page = await browser.newPage();
         // 頁(yè)眉
        let headerTemplate = "";
        // 頁(yè)腳
        let footerTemplate = "";
        {
            // 構(gòu)建頁(yè)眉
            console.log("headerTemplate");
            let dom = new JSDOM(htmlString);
            let document = dom.window.document;
            const elementsToRemove = document.querySelectorAll(".page_start");
            if(elementsToRemove.length > 0) {
                headerTemplate = elementsToRemove[0].outerHTML;
            }
            elementsToRemove.forEach(el => el.parentNode.removeChild(el));  
            updatedHtmlString = dom.serialize();
        }
        {
            // 構(gòu)建頁(yè)腳
            console.log("footerTemplate");
            dom = new JSDOM(updatedHtmlString);
            document = dom.window.document;
            const endelementsToRemove = document.querySelectorAll(".page_end");
            if(endelementsToRemove.length > 0) {
                footerTemplate = endelementsToRemove[0].outerHTML;
            }
            endelementsToRemove.forEach(el => el.parentNode.removeChild(el));  
            updatedHtmlString = dom.serialize();
        }
        // 設(shè)置HTML內(nèi)容并生成PDF的Buffer
        await page.setContent(updatedHtmlString);
        // 設(shè)置 PDF 選項(xiàng)
        const pdfOptions = {
            path: 'example.pdf',
            format: 'a4',
            displayHeaderFooter: true,
            headerTemplate,
            footerTemplate,
            margin: {
                top: '60px',
                bottom: '20px',
                left: '20px',
                right: '50px'
            },
        };
        // 生成 PDF
         // 如果要生成帶著 screen media的pdf,在page.pdf() 前面先調(diào)用 page.emulateMedia('screen')
        const pdfBuffer = await page.pdf(pdfOptions);
        return pdfBuffer;
    } catch(error) {
        console.log(error);
    }
}
module.exports = {
    getBrowserInstance,
    generatePDFFromHTML
}

4. DockerFile

FROM ghcr.io/puppeteer/puppeteer:latest
MAINTAINER weiqlog@126.com
USER root
RUN mkdir -p /pdfG
WORKDIR /pdfG
COPY package*.json ./
COPY . .
RUN npm instal
EXPOSE 10030
ENTRYPOINT ["node", "main.js", "10030"]

使用:

docker pull 1505774577/html_to_pdf:1.0.0.dev
docker run -d -p 10030:10030 --cap-add=SYS_ADMIN 1505774577/html_to_pdf:1.0.0.dev

以上就是Docker平臺(tái)下NodeJs Puppeteer實(shí)現(xiàn)html轉(zhuǎn)pdf過程示例的詳細(xì)內(nèi)容,更多關(guān)于Docker 平臺(tái) NodeJs Puppeteer實(shí)現(xiàn)html轉(zhuǎn)pdf的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • npm報(bào)錯(cuò):npm?WARN?config?global?'--global',?'--local'?are?deprecated解決

    npm報(bào)錯(cuò):npm?WARN?config?global?'--global',?&apo

    這篇文章主要給大家介紹了關(guān)于npm報(bào)錯(cuò):npm?WARN?config?global?'--global',?'--local'?are?deprecated.?Use?`--location=global`?instead.的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • NodeJS使用文件流解決大文件處理的內(nèi)存與時(shí)間效率問題

    NodeJS使用文件流解決大文件處理的內(nèi)存與時(shí)間效率問題

    在 NodeJS 中,文件操作是常見的任務(wù)之一,然而,當(dāng)處理大文件時(shí),直接將整個(gè)文件加載到內(nèi)存中可能會(huì)導(dǎo)致內(nèi)存溢出或性能瓶頸,為了解決這一問題,NodeJS 提供了文件流(Stream)機(jī)制,本文將詳細(xì)介紹文件流的優(yōu)點(diǎn)、使用方法、應(yīng)用場(chǎng)景,并探討背壓(Backpressure)的概念
    2025-01-01
  • NodeJS遠(yuǎn)程代碼執(zhí)行

    NodeJS遠(yuǎn)程代碼執(zhí)行

    這篇文章主要介紹了NodeJS遠(yuǎn)程代碼執(zhí)行方法的相關(guān)資料,需要的朋友可以參考下
    2016-08-08
  • express框架,報(bào)錯(cuò):“Cannot set headers after they are sent to the client”,解決方法總結(jié)

    express框架,報(bào)錯(cuò):“Cannot set headers after t

    這篇文章主要介紹了express框架,報(bào)錯(cuò):“Cannot set headers after they are sent to the client”,解決方法,結(jié)合實(shí)例形式總結(jié)分析了常見的問題原因與對(duì)應(yīng)的解決方案,需要的朋友可以參考下
    2023-05-05
  • node.js中使用node-schedule實(shí)現(xiàn)定時(shí)任務(wù)實(shí)例

    node.js中使用node-schedule實(shí)現(xiàn)定時(shí)任務(wù)實(shí)例

    這篇文章主要介紹了node.js中使用node-schedule實(shí)現(xiàn)定時(shí)任務(wù)實(shí)例,包括安裝方法和4種使用例子,需要的朋友可以參考下
    2014-06-06
  • Dapr+NestJs編寫Pub及Sub裝飾器實(shí)戰(zhàn)示例

    Dapr+NestJs編寫Pub及Sub裝飾器實(shí)戰(zhàn)示例

    這篇文章主要為大家介紹了Dapr+NestJs編寫Pub及Sub裝飾器的實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 深入理解Node.js中import.meta的使用

    深入理解Node.js中import.meta的使用

    import.meta提供模塊的上下文信息,如文件URL、解析模塊路徑、判斷模塊是否為入口等,本文就來(lái)介紹一下Node.js中import.meta的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2026-01-01
  • Nodejs+angularjs結(jié)合multiparty實(shí)現(xiàn)多圖片上傳的示例代碼

    Nodejs+angularjs結(jié)合multiparty實(shí)現(xiàn)多圖片上傳的示例代碼

    這篇文章主要介紹了Nodejs+angularjs結(jié)合multiparty實(shí)現(xiàn)多圖片上傳的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • 圖文詳解如何開發(fā)一個(gè)自己的包并發(fā)布到npm

    圖文詳解如何開發(fā)一個(gè)自己的包并發(fā)布到npm

    前端開發(fā)將自己編寫的常用組件、工具模塊、指令,常用api庫(kù)、框架等代碼,為了能夠更好、更靈活的管理這些代碼,上傳到npm庫(kù)是一個(gè)非常好的選擇方式,這篇文章主要介紹了如何開發(fā)一個(gè)自己的包并發(fā)布到npm的相關(guān)資料,需要的朋友可以參考下
    2025-10-10
  • nodejs實(shí)現(xiàn)套接字服務(wù)功能詳解

    nodejs實(shí)現(xiàn)套接字服務(wù)功能詳解

    這篇文章主要介紹了nodejs實(shí)現(xiàn)套接字服務(wù)功能,簡(jiǎn)單描述了套接字的概念、功能,并結(jié)合實(shí)例形式分析了nodejs使用socket對(duì)象創(chuàng)建及使用套接字進(jìn)行數(shù)據(jù)傳輸相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-06-06

最新評(píng)論

义乌市| 泰兴市| 同德县| SHOW| 景洪市| 中山市| 顺昌县| 平安县| 上虞市| 台东县| 苍南县| 成都市| 乐清市| 金阳县| 成安县| 前郭尔| 苏尼特右旗| 仁布县| 泰安市| 朝阳区| 尚志市| 太湖县| 宜兰县| 修武县| 临沂市| 潜山县| 鄱阳县| 出国| 隆德县| 哈密市| 渝中区| 高唐县| 淄博市| 张家港市| 亳州市| 磐石市| 灵石县| 晋州市| 祥云县| 南漳县| 徐汇区|