如何在Next.js/React Native中无需预签名链接显示S3存储的PDF
解决方案
核心原因分析
你的S3常规URL无法在谷歌文档查看器中显示,本质是S3对象默认私有,谷歌的服务器无法访问该资源;另外你第一段代码存在URL拼接错误(${pdf_url}pdf多追加了pdf后缀)。下面是无需预签名链接的可行方案:
方案1:配置S3权限允许公开/第三方访问
首先需要让S3对象能被外部服务或浏览器直接访问,二选一即可:
方式1:设置对象ACL为公开读
在AWS S3控制台找到目标PDF文件,修改其权限为对象所有人拥有读权限,常规URL就能直接被外部访问。
方式2:配置Bucket Policy(推荐,更安全)
如果不想完全公开所有对象,可在S3桶的权限页面添加Bucket Policy,仅允许谷歌文档查看器的域名访问目标路径:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::myprojectchatpdf/uploads/*", "Condition": { "StringLike": { "aws:Referer": "https://docs.google.com/*" } } } ] }
然后修正React组件代码(去掉多余的pdf后缀,同时编码URL):
type PDFViewerProps = { pdf_url: string }; export default function PDFViewer({ pdf_url }: PDFViewerProps) { const encodedUrl = encodeURIComponent(pdf_url); return ( <iframe src={`https://docs.google.com/gview?url=${encodedUrl}&embedded=true`} title="pdf-viewer" className="w-full h-full" /> ); }
方案2:使用PDF.js本地渲染(无需依赖第三方服务)
如果不想依赖谷歌文档查看器,可直接用Mozilla的PDF.js库在页面内渲染PDF,稳定性更高,且无第三方服务限制:
Next.js/React 实现
- 安装依赖:
npm install react-pdf
- 组件示例:
import { Document, Page, pdfjs } from 'react-pdf'; import 'react-pdf/dist/esm/Page/AnnotationLayer.css'; import 'react-pdf/dist/esm/Page/TextLayer.css'; // 配置PDF.js的worker路径 pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`; type PDFViewerProps = { pdf_url: string }; export default function PDFViewer({ pdf_url }: PDFViewerProps) { return ( <div className="w-full h-full"> <Document file={pdf_url}> <Page pageNumber={1} /> {/* 如需多页可循环渲染,或添加分页控件 */} </Document> </div> ); }
React Native 实现
使用react-native-pdf库:
- 安装依赖:
npm install react-native-pdf react-native-blob-util # iOS需额外执行 pod install
- 组件示例:
import PDFView from 'react-native-pdf'; export default function PDFViewer({ pdf_url }) { return ( <PDFView style={{ flex: 1 }} source={{ uri: pdf_url }} onLoadComplete={(numberOfPages) => console.log(`总页数:${numberOfPages}`)} /> ); }
方案3:直接用iframe访问公开的S3 PDF
如果已经将S3对象设置为公开读,无需第三方服务,直接用iframe加载S3 URL即可:
type PDFViewerProps = { pdf_url: string }; export default function PDFViewer({ pdf_url }: PDFViewerProps) { return ( <iframe src={pdf_url} title="pdf-viewer" className="w-full h-full" type="application/pdf" /> ); }
注:部分浏览器可能会直接下载PDF而非内嵌显示,此时仍推荐使用方案2的PDF.js渲染方式。
内容的提问来源于stack exchange,提问作者sudipta paul
相关产品推荐
相关产品推荐

