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
相关产品推荐
相关产品推荐

