You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在Firebase Function中使用PhantomJS实现URL转PDF截图示例求助

刚好之前帮朋友实现过类似的需求,给你分享一个完整的可运行案例,涵盖从依赖安装到部署测试的全流程,亲测在Firebase Functions环境下可用:

在Firebase Functions中用PhantomJS生成PDF截图的实现方案

前置准备

  • 确保你已经初始化了Firebase项目,本地安装了firebase-tools并完成了登录
  • 注意:PhantomJS对Node.js版本有一定兼容性要求,建议使用Node 16或18版本(高版本Node可能会出现依赖安装问题)

安装依赖

在你的functions目录下执行以下命令安装所需包:

npm install phantomjs-prebuilt firebase-functions@latest firebase-admin@latest --save

这里选用phantomjs-prebuilt是因为它会自动适配不同平台的二进制文件,完美兼容Firebase的云运行环境

完整代码实现

我们需要两个文件:一个是Firebase Function的主逻辑,另一个是PhantomJS的截图脚本。

1. HTTP触发的Function主文件(index.js)

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const phantom = require('phantomjs-prebuilt');
const fs = require('fs');
const path = require('path');

admin.initializeApp();

exports.generatePdfFromUrl = functions.https.onRequest(async (req, res) => {
  // 第一步:验证请求参数是否存在
  const targetUrl = req.query.url;
  if (!targetUrl) {
    return res.status(400).send('请在请求参数中传入目标URL(?url=xxx)');
  }

  // 第二步:创建临时文件路径(Firebase Functions仅允许/tmp目录可写)
  const tempPdfPath = path.join('/tmp', `${Date.now()}.pdf`);

  let phantomProcess;
  try {
    // 第三步:启动PhantomJS进程,执行截图脚本
    phantomProcess = phantom.exec(
      path.join(__dirname, 'pdf-generator.js'),
      targetUrl,
      tempPdfPath
    );

    // 等待PhantomJS完成PDF生成
    await new Promise((resolve, reject) => {
      phantomProcess.on('exit', (code) => {
        code === 0 ? resolve() : reject(new Error(`PhantomJS执行失败,退出码:${code}`));
      });
      phantomProcess.on('error', reject);
    });

    // 第四步:读取生成的PDF并返回给客户端
    const pdfBuffer = fs.readFileSync(tempPdfPath);
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', `inline; filename="页面快照-${Date.now()}.pdf"`);
    res.send(pdfBuffer);
  } catch (error) {
    functions.logger.error('PDF生成失败:', error);
    res.status(500).send(`PDF生成失败:${error.message}`);
  } finally {
    // 第五步:清理临时文件和进程
    if (fs.existsSync(tempPdfPath)) {
      fs.unlinkSync(tempPdfPath);
    }
    if (phantomProcess) {
      phantomProcess.kill();
    }
  }
});

2. PhantomJS截图脚本(pdf-generator.js)

把这个文件放在functions目录下,和index.js同级:

// pdf-generator.js
const page = require('webpage').create();
const system = require('system');

// 验证参数数量
if (system.args.length !== 3) {
  console.error('参数错误:请传入目标URL和输出路径');
  phantom.exit(1);
}

const targetUrl = system.args[1];
const outputPath = system.args[2];

// 配置页面渲染参数
page.viewportSize = { width: 1280, height: 720 };
page.paperSize = {
  format: 'A4',
  orientation: 'portrait',
  margin: '1cm'
};

page.open(targetUrl, (status) => {
  if (status !== 'success') {
    console.error(`无法加载目标URL:${targetUrl}`);
    phantom.exit(1);
  }

  // 等待页面异步内容加载完成(可根据页面复杂度调整等待时间)
  setTimeout(() => {
    page.render(outputPath, { format: 'pdf' });
    console.log(`PDF已生成至:${outputPath}`);
    phantom.exit(0);
  }, 2000);
});

部署与测试

  1. 部署函数到Firebase:
firebase deploy --only functions:generatePdfFromUrl
  1. 测试函数:访问部署后的函数URL,加上?url=目标网址参数即可,比如:
https://<你的项目区域>-<你的项目ID>.cloudfunctions.net/generatePdfFromUrl?url=https://example.com

关键注意事项

  • 超时设置:Firebase Functions默认超时60秒,如果你的目标页面加载较慢,可在firebase.json中调整超时时间(最大900秒):
    {
      "functions": {
        "runtimeOptions": {
          "timeoutSeconds": 120
        }
      }
    }
    
  • 资源限制:PhantomJS对内存和CPU占用较高,如果请求量较大,建议升级Firebase Functions的实例规格
  • 页面兼容性:部分网站会拦截无头浏览器访问,遇到这种情况可以给PhantomJS添加自定义User-Agent
  • 依赖问题:如果安装phantomjs-prebuilt失败,可尝试指定兼容版本:npm install phantomjs-prebuilt@2.1.16 --save

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

火山引擎 最新活动