You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Puppeteer和adm-zip批量生成PDF时出现Node加密哈希错误

问题分析

你遇到的node:internal/crypto/hash:113错误,本质是adm-zip的addFile方法接收到了无效的内容数据(比如undefined),触发了底层哈希计算的异常。结合你的场景:仅特定视图批量生成时出错、单个生成正常,问题出在循环中某个特定ID对应的PDF生成失败,但代码仍继续执行,将未定义的pdf传入了zip.addFile。

大概率是以下某类原因:

  • 特定视图的页面加载未完成(比如networkidle0等待条件未满足,页面资源加载超时)
  • 特定视图中不存在gerar-pdf按钮,导致page.evaluate抛出异常,后续page.pdf未执行
  • 特定页面的内容渲染异常,导致page.pdf生成失败
解决方案

1. 严格校验PDF数据,避免无效内容传入压缩包

在调用zip.addFile前,先检查pdf是否有效,无效则跳过该文件:

const pdf = await page.pdf({ format: 'A4', printBackground: true, pageRanges: '1' });
// 校验pdf是否为有效Buffer
if (pdf && Buffer.isBuffer(pdf)) {
  zip.addFile(`${id}.pdf`, pdf, `PDF para o ID ${id}`);
} else {
  console.warn(`跳过无效PDF: ID ${id}`);
}

2. 优化页面加载与错误处理

  • 给页面加载添加超时时间,避免无限等待:
await page.goto(url, {waitUntil: 'networkidle0', timeout: 30000}); // 30秒超时
  • 处理gerar-pdf按钮不存在的情况,避免page.evaluate抛出异常:
await page.evaluate(() => {
  const button = document.getElementById('gerar-pdf');
  if (button) button.remove(); // 先判断按钮存在再移除
});

3. 隔离页面上下文,避免跨页面污染

批量生成时复用单个页面可能导致上下文残留,尝试为每个ID创建新页面:

// 移除全局的page变量,在循环内创建新页面
for (let i = 0; i < idsArray.length; i++) {
  const id = idsArray[i];
  const url = `http://${IP}:${port}/${database}/${tipo}/${id}`;
  console.log(url);
  try {
    const page = await browser.newPage(); // 每个ID创建新页面
    await page.goto(url, {waitUntil: 'networkidle0', timeout: 30000});
    await page.evaluate(() => {
      const button = document.getElementById('gerar-pdf');
      if (button) button.remove();
    });
    const pdf = await page.pdf({ format: 'A4', printBackground: true, pageRanges: '1' });
    if (pdf && Buffer.isBuffer(pdf)) {
      zip.addFile(`${id}.pdf`, pdf, `PDF para o ID ${id}`);
    }
    await page.close(); // 及时关闭页面释放资源
  } catch (err) {
    console.error(`处理ID ${id}时出错:`, err.stack);
  }
}

4. 排查特定视图的异常

针对触发错误的特定ID,单独访问对应的URL,检查:

  • 页面是否能正常加载,无控制台报错
  • gerar-pdf按钮是否存在
  • 页面渲染是否完整(比如是否有动态加载的内容未完成)
修改后的完整代码示例
router.get('/:database/:tipo/:ids/:limite?.zip', async (req, res) => {
  const { database, tipo, ids, limite } = req.params;

  let idsArray;
  if (ids === "ids") {
    const pool = new Pool({
      user: process.env.POSTGRES_USER,
      host: process.env.POSTGRES_HOST,
      database: database,
      password: process.env.POSTGRES_PASSWORD,
      port: process.env.POSTGRES_PORT,
    });

    let query = `SELECT id FROM controle_interno.${tipo} ORDER BY id ASC`;
    if (limite) {
      query += ` LIMIT ${limite}`;
    }
    const result = await pool.query(query);
    idsArray = result.rows.map(row => row.id);
  } else {
    idsArray = ids.split(",");
  }

  const zip = new AdmZip();
  const browser = await puppeteer.launch({
    args: ['--disable-gpu', '--disable-software-rasterizer', '--disable-dev-shm-usage', '--disable-setuid-sandbox', '--no-sandbox']
  });

  for (let i = 0; i < idsArray.length; i++) {
    const id = idsArray[i];
    const url = `http://${IP}:${port}/${database}/${tipo}/${id}`;
    console.log(url);
    try {
      const page = await browser.newPage();
      await page.goto(url, {waitUntil: 'networkidle0', timeout: 30000});
      await page.evaluate(() => {
        const button = document.getElementById('gerar-pdf');
        if (button) button.remove();
      });
      const pdf = await page.pdf({ format: 'A4', printBackground: true, pageRanges: '1' });
      if (pdf && Buffer.isBuffer(pdf)) {
        zip.addFile(`${id}.pdf`, pdf, `PDF para o ID ${id}`);
      } else {
        console.warn(`ID ${id}未生成有效PDF`);
      }
      await page.close();
    } catch (err) {
      console.error(`处理ID ${id}出错:`, err.stack);
    }
  }

  await browser.close();
  const zipBuffer = zip.toBuffer();

  res.set({
    'Content-Type': 'application/zip',
    'Content-Disposition': `attachment; filename=${tipo}.zip`,
    'Content-Length': zipBuffer.length
  });

  res.send(zipBuffer);
});
module.exports = router;

内容的提问来源于stack exchange,提问作者lucasmsqt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:53:11