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

Node.js Serverless API返回PDF文件损坏问题求助

解决Serverless框架下Node.js API返回PDF损坏、React-PDF加载失败的问题

问题根源

API Gateway(包括serverless-offline的本地模拟)默认会对非文本响应做base64编码/解码处理,若配置不当,会导致二进制PDF数据被错误转换(比如被当成UTF-8文本解析),出现字节差异,最终让React-PDF无法正常解析,触发Warning: Indexing all PDF objects警告。

具体解决方案

1. 修正serverless.yml的二进制配置

确保API Gateway和serverless-offline都正确识别PDF的MIME类型,添加以下配置:

provider:
  name: aws
  runtime: nodejs18.x # 替换为你使用的Node.js版本
  apiGateway:
    # 配置API Gateway允许的二进制媒体类型
    binaryMediaTypes:
      - 'application/pdf'
      - 'application/octet-stream' # 兜底覆盖其他二进制类型

plugins:
  - serverless-offline

custom:
  # 给serverless-offline单独配置二进制类型,避免本地模拟不生效
  serverless-offline:
    binaryMediaTypes:
      - 'application/pdf'
      - 'application/octet-stream'

2. 调整API处理代码

根据你使用的是Express+serverless-http还是原生Lambda handler,分别处理:

场景1:Express + serverless-http包装

确保Express不对PDF请求做文本解析,响应时直接发送Buffer:

const express = require('express');
const serverless = require('serverless-http');
const fs = require('fs').promises;
const path = require('path');

const app = express();

// 仅在需要JSON接口时保留以下解析中间件,否则注释/删除,避免干扰二进制响应
// app.use(express.json());
// app.use(express.urlencoded({ extended: true }));

// PDF接口路由
app.get('/api/pdf', async (req, res) => {
  try {
    const pdfBuffer = await fs.readFile(path.join(__dirname, 'target-pdf.pdf'));
    // 设置严格的响应头
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', 'inline; filename="document.pdf"');
    // 直接发送Buffer,serverless-http会自动处理base64编码
    res.send(pdfBuffer);
  } catch (err) {
    res.status(500).send('Failed to load PDF');
  }
});

module.exports.handler = serverless(app);

场景2:原生Lambda Handler

必须手动设置isBase64Encoded: true,并将Buffer转为base64字符串:

const fs = require('fs').promises;
const path = require('path');

module.exports.getPDF = async (event) => {
  try {
    const pdfBuffer = await fs.readFile(path.join(__dirname, 'target-pdf.pdf'));
    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/pdf',
        'Content-Disposition': 'inline; filename="document.pdf"'
      },
      body: pdfBuffer.toString('base64'),
      isBase64Encoded: true // 关键:告诉API Gateway这是base64编码的二进制数据
    };
  } catch (err) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Failed to load PDF' })
    };
  }
};

3. 前端React-PDF请求优化

确保请求时明确获取Blob类型,避免浏览器自动解析为文本:

import { useState, useEffect } from 'react';
import { Document, Page } from 'react-pdf';

export default function PDFViewer() {
  const [pdfBlobUrl, setPdfBlobUrl] = useState(null);

  useEffect(() => {
    fetch('/.netlify/functions/getPDF') // 替换为你的Serverless API URL
      .then(response => {
        if (!response.ok) throw new Error('Request failed');
        return response.blob(); // 明确获取Blob类型
      })
      .then(blob => {
        const url = URL.createObjectURL(blob);
        setPdfBlobUrl(url);
      })
      .catch(err => console.error('Load PDF error:', err));

    // 组件卸载时释放Blob URL
    return () => {
      if (pdfBlobUrl) URL.revokeObjectURL(pdfBlobUrl);
    };
  }, []);

  return (
    pdfBlobUrl ? (
      <Document file={pdfBlobUrl}>
        <Page pageNumber={1} />
      </Document>
    ) : (
      <div>Loading PDF...</div>
    )
  );
}

4. serverless-offline额外调试步骤

  • 更新serverless-offline到最新版本:npm update serverless-offline,旧版本存在二进制处理的bug。
  • 清除本地缓存:删除项目根目录下的.node_modules/.cache/serverless-offline文件夹,避免旧配置残留。
  • 启动时添加--verbose参数查看日志:serverless offline --verbose,检查二进制请求是否被正确识别。

关键检查点

  • 确认Content-Type头严格为application/pdf,不要添加额外空格或参数。
  • 对比返回的PDF字节时,确保Serverless环境下的响应是正确的二进制数据,而非被UTF-8转换后的文本。
  • 对于serverless-http,确保没有中间件篡改响应的Buffer数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 12:01:07