pdf.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. const { PATH_FILES } = require('../config')
  2. const logger = require('../log/index')
  3. const puppeteer = require('puppeteer');
  4. const fs = require('fs')
  5. const path = require('path')
  6. // 生成
  7. async function initBrowser () {
  8. logger.log.debug('启动', new Date().toLocaleString())
  9. return await puppeteer.launch({
  10. headless: true,
  11. args: [
  12. '--no-sandbox',
  13. '--disable-setuid-sandbox',
  14. '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'
  15. ]
  16. });
  17. }
  18. let browser = null
  19. function checkCache (fPath) {
  20. try {
  21. const fStat = fs.statSync(fPath)
  22. if (fStat) {
  23. const isFile = fStat.isFile()
  24. if (isFile) {
  25. return fPath
  26. }
  27. }
  28. return false
  29. } catch (err) {
  30. return false
  31. }
  32. }
  33. function wait(ms) {
  34. return new Promise((resolve, reject) => {
  35. setTimeout(() => {
  36. console.log("Done waiting");
  37. resolve(ms)
  38. }, ms)
  39. })
  40. }
  41. function asyncCheck(delay, step, delayFn) {
  42. return new Promise((resolve, reject) => {
  43. let attempts = 0;
  44. const maxAttempts = Math.ceil(delay / step); // 计算最大尝试次数
  45. const check = () => {
  46. delayFn().then(result => {
  47. if (result) {
  48. resolve({ result: true, type: 'check' });
  49. } else {
  50. attempts++;
  51. if (attempts > maxAttempts) {
  52. resolve({ result: false, type: 'max' });
  53. } else {
  54. // 如果还没有达到最大尝试次数,继续查询
  55. setTimeout(check, step);
  56. }
  57. }
  58. }).catch(error => {
  59. // 如果delayFn抛出错误,拒绝Promise
  60. logger.log.debug('检查页面状态失败', error)
  61. setTimeout(() => {
  62. resolve({ result: false, type: 'max-error' });
  63. }, delay)
  64. });
  65. };
  66. // 启动定时查询
  67. check();
  68. });
  69. }
  70. async function createPDFOfURL (url, config = {}) {
  71. if (!browser) {
  72. browser = await initBrowser()
  73. }
  74. config = Object.assign( {
  75. filename: '',
  76. dir: '',
  77. nocache: false,
  78. width: '950px',
  79. height: '1360px',
  80. margin: {
  81. top: 0,
  82. bottom: 0
  83. },
  84. step: 200,
  85. check: true
  86. }, config)
  87. // 文件路径
  88. const outPath = path.join(PATH_FILES, config.dir)
  89. if (!fs.existsSync(outPath)) {
  90. fs.mkdirSync(outPath);
  91. }
  92. const outConfig = Object.assign({path: `${config.filename}.pdf`, width: config.width, height: config.height,printBackground: true }, config)
  93. outConfig.path = path.join(outPath, outConfig.path)
  94. // 检查缓存
  95. if (!config.nocache) {
  96. const result = checkCache(outConfig.path)
  97. if (result) {
  98. logger.log.debug('命中缓存文件')
  99. return result
  100. }
  101. }
  102. const page = await browser.newPage();
  103. try {
  104. await page.setDefaultNavigationTimeout(0)
  105. page.on('console', async (message) => {
  106. const args = await Promise.all(message.args().map(arg => arg.jsonValue()));
  107. logger.log.debug(`page log: ${message.type()}: ${message.text()} args: ${JSON.stringify(args)}`);
  108. });
  109. await page.on('response', (response) => {
  110. if (response.status() !== 200) {
  111. logger.log.debug(`Res error: ${response.status()} ${response.url()}`)
  112. }
  113. });
  114. await page.goto(url, {waitUntil: 'networkidle2'});
  115. logger.log.debug('等待生成', new Date().toLocaleString())
  116. if (config.check) {
  117. await asyncCheck(config.delay, config.step, async () => {
  118. const result = await page.evaluate(() => {
  119. return window.__PDF_LOADED__ || false
  120. })
  121. logger.log.debug('页面 __PDF_LOADED__ 状态检查', result)
  122. return result
  123. })
  124. } else {
  125. await wait(config.delay || 1000)
  126. }
  127. await page.pdf(outConfig);
  128. await page.close();
  129. logger.log.debug('当前时间', new Date().toLocaleString())
  130. return outConfig.path
  131. } catch (e) {
  132. logger.log.debug(e)
  133. await page.close();
  134. }
  135. }
  136. module.exports = createPDFOfURL