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

基于Node.js+Express.js提取PDF指定页面的实现方案咨询

实现Express返回PDF指定页面的解决方案

核心方案

使用 pdf-lib 库(轻量、基于Promise的PDF操作工具),加载目标PDF后提取指定页面生成新的PDF文档,再将其作为响应返回给客户端。

步骤实现

1. 安装依赖

npm install pdf-lib express

2. 编写Express路由代码

const express = require('express');
const { PDFDocument } = require('pdf-lib');
const fs = require('fs').promises;
const path = require('path');

const app = express();
const PORT = 3000;

// 限制PDF文件只能从指定目录读取,防止路径遍历攻击
const ALLOWED_PDF_DIR = path.resolve(__dirname, 'pdfs');

app.get('/file', async (req, res) => {
  try {
    const { file, page } = req.query;

    // 参数校验
    if (!file || !page) {
      return res.status(400).send('缺少必要参数:file 和 page');
    }

    const targetPageNum = parseInt(page, 10);
    if (isNaN(targetPageNum) || targetPageNum < 1) {
      return res.status(400).send('page 必须是正整数');
    }

    // 处理文件路径,确保在允许的目录内
    const filePath = path.resolve(ALLOWED_PDF_DIR, file);
    if (!filePath.startsWith(ALLOWED_PDF_DIR)) {
      return res.status(403).send('无权访问该文件');
    }

    // 读取原PDF文件
    const originalPdfBytes = await fs.readFile(filePath);
    const originalPdf = await PDFDocument.load(originalPdfBytes);
    const totalPages = originalPdf.getPageCount();

    // 校验页码是否超出范围
    if (targetPageNum > totalPages) {
      return res.status(400).send(`该PDF仅包含${totalPages}页,无法获取第${targetPageNum}页`);
    }

    // 创建新PDF并复制指定页面(注意pdf-lib页码从0开始)
    const newPdf = await PDFDocument.create();
    const [targetPage] = await newPdf.copyPages(originalPdf, [targetPageNum - 1]);
    newPdf.addPage(targetPage);

    // 生成新PDF的字节数据
    const newPdfBytes = await newPdf.save();

    // 设置响应头,返回PDF
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', `inline; filename="${path.parse(file).name}_page${targetPageNum}.pdf"`);
    res.send(newPdfBytes);
  } catch (err) {
    console.error('处理请求出错:', err);
    if (err.code === 'ENOENT') {
      return res.status(404).send('指定PDF文件不存在');
    }
    res.status(500).send('服务器内部错误');
  }
});

app.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
});

关键注意事项

  • 路径安全:必须通过ALLOWED_PDF_DIR限制文件读取范围,避免用户通过file参数构造路径遍历攻击(比如file=../secret.pdf)
  • 错误处理:覆盖了参数缺失、页码无效、文件不存在、服务器异常等多种场景,确保响应友好
  • 性能优化:如果频繁请求同一PDF的同一页面,可以考虑加入缓存机制(比如内存缓存或Redis),避免重复解析PDF
  • 替代方案:若需要更底层的PDF操作,可尝试hummus.js,但pdf-lib的API更简洁,更适合Express的异步场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:22:24