如何用PDF.js显示AWS S3存储的PDF文件而非直接下载?
解决PDF.js无法展示S3存储PDF的问题
我之前也碰到过类似的情况,核心原因主要是S3资源的响应头配置、跨域权限,以及PDF.js的调用方式不对,咱们一步步来解决:
1. 先修正S3文件的Content-Type
浏览器判断是显示还是下载文件,很大程度取决于服务器返回的Content-Type头。S3默认上传的文件如果没指定类型,会被设为application/octet-stream,浏览器就会直接触发下载。
- 打开S3控制台,找到你的PDF文件,右键选「属性」
- 拉到「元数据」区域,检查
Content-Type是否为application/pdf- 如果不是,点击「编辑」,添加/修改这个键值对
- 批量文件的话,可以用AWS CLI命令批量更新:
aws s3 cp s3://你的桶名/ s3://你的桶名/ --exclude "*" --include "*.pdf" --content-type "application/pdf" --metadata-directive REPLACE --recursive
2. 配置S3桶的CORS规则
你的网页在EC2上,访问S3资源属于跨域请求,PDF.js需要读取S3文件的内容,必须让S3允许这个跨域请求:
- 进入S3桶的「权限」标签,找到「跨域资源共享(CORS)」
- 替换成类似这样的规则(把
AllowedOrigins改成你EC2网页的域名/IP,测试阶段可以暂时用["*"],生产环境一定要限制具体域名):[ { "AllowedHeaders": ["*"], "AllowedMethods": ["GET"], "AllowedOrigins": ["https://你的EC2域名"], "ExposeHeaders": [] } ]
3. 用PDF.js的API加载S3链接,别直接用a标签
你之前的代码用了a标签指向S3链接,浏览器会直接处理成下载。正确的做法是调用PDF.js的getDocument方法来加载文件:
先确保引入了PDF.js的库和工作器:
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js"></script>
然后替换成这样的渲染代码:
<div id="wrap"> <div id="pdf-container"></div> </div> <script> // S3的PDF链接(如果是私有文件,这里要换成预签名URL) const pdfUrl = 'https://s3-eu-west-myPath/rab3.7M.pdf'; // 加载并渲染PDF pdfjsLib.getDocument(pdfUrl).promise.then(pdf => { // 渲染第一页,你可以扩展成渲染所有页 return pdf.getPage(1); }).then(page => { const container = document.getElementById('pdf-container'); const viewport = page.getViewport({ scale: 1.2 }); // 调整缩放比例 // 创建canvas用于渲染 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = viewport.width; canvas.height = viewport.height; container.appendChild(canvas); // 渲染页面到canvas const renderCtx = { canvasContext: ctx, viewport: viewport }; return page.render(renderCtx).promise; }).catch(err => { console.error('PDF加载失败:', err); }); </script>
额外注意点:私有S3文件的处理
如果你的S3桶是私有的,直接的公开链接无法访问,需要生成预签名URL:
- 可以在后端用AWS SDK(比如Node.js、Python)生成,然后传给前端
- 预签名URL有过期时间,按需生成即可
内容的提问来源于stack exchange,提问作者jamesMcKey




