React应用中如何渲染通过Express后端代理获取的PDF内容
React应用中如何渲染通过Express后端代理获取的PDF内容
兄弟,我懂你现在的困境——通过Express代理拿到PDF后,React里用object标签死活渲染不出来,连替代文本都没显示。别着急,咱们先从后端的问题入手,再解决前端的渲染方式,一步步搞定。
第一步:修复Express后端的PDF获取逻辑
你当前的后端代码有个关键问题:axios默认会把响应解析成JSON格式,但PDF是二进制数据,直接这么处理会把数据搞乱,导致前端拿到的是损坏的内容。必须给axios请求加上responseType: 'arraybuffer',确保拿到原始的二进制PDF数据。
修改后的后端代码:
router.get('/fetch-pdf-content', async (req, res) => { try { // 核心:设置responseType为arraybuffer,保留PDF的二进制结构 const { data } = await axios.get('https://abc.pdf', { responseType: 'arraybuffer' }); res.contentType('application/pdf'); // 把二进制数据转成Buffer发送给前端 res.send(Buffer.from(data)); } catch (error) { console.error(error); res.status(500).send(error.code || '获取PDF失败'); } })
第二步:前端渲染PDF的两种可靠方式
后端修复后,前端就可以用更稳定的方式渲染PDF了,这里给你两种方案:
方案一:用Blob URL配合object/iframe(简单直接)
直接用后端URL有时候会因为浏览器缓存、响应头解析等问题出问题,我们可以先把后端返回的PDF转成Blob,再创建临时的Blob URL,这样渲染更可靠。
React组件示例:
import { useState, useEffect } from 'react'; function PdfViewer() { const [pdfUrl, setPdfUrl] = useState(null); useEffect(() => { const fetchAndPreparePdf = async () => { try { const response = await fetch('http://localhost:5000/fetch-pdf-content'); if (!response.ok) throw new Error('加载PDF失败'); // 把响应转成Blob对象 const pdfBlob = await response.blob(); // 创建临时的Blob URL const tempUrl = URL.createObjectURL(pdfBlob); setPdfUrl(tempUrl); // 组件卸载时清理URL,避免内存泄漏 return () => URL.revokeObjectURL(tempUrl); } catch (err) { console.error('PDF加载出错:', err); } }; fetchAndPreparePdf(); }, []); if (!pdfUrl) { return <div>正在加载PDF...</div>; } return ( <div style={{ width: '100%', height: '80vh' }}> {/* 用object标签,也可以替换成iframe,兼容性更好 */} <object data={pdfUrl} type="application/pdf" style={{ width: '100%', height: '100%' }} > <p>无法直接预览PDF,你可以<a href={pdfUrl} download="document.pdf">点击下载</a>查看。</p> </object> </div> ); } export default PdfViewer;
方案二:用react-pdf库(功能更强大)
如果需要分页、缩放、搜索这些进阶功能,推荐用react-pdf库,它对PDF的渲染控制更灵活。
首先安装依赖:
npm install react-pdf
然后写组件:
import { useState, useEffect } from 'react'; import { Document, Page } from 'react-pdf'; // 别忘了引入样式,否则文本层和注释层会显示异常 import 'react-pdf/dist/esm/Page/AnnotationLayer.css'; import 'react-pdf/dist/esm/Page/TextLayer.css'; function AdvancedPdfViewer() { const [pdfUrl, setPdfUrl] = useState(null); const [totalPages, setTotalPages] = useState(null); const [currentPage, setCurrentPage] = useState(1); useEffect(() => { const fetchPdf = async () => { try { const response = await fetch('http://localhost:5000/fetch-pdf-content'); if (!response.ok) throw new Error('获取PDF失败'); const blob = await response.blob(); setPdfUrl(URL.createObjectURL(blob)); return () => URL.revokeObjectURL(blob); } catch (err) { console.error(err); } }; fetchPdf(); }, []); const handleDocumentLoad = ({ numPages }) => { setTotalPages(numPages); }; if (!pdfUrl) { return <div>加载中...</div>; } return ( <div style={{ width: '100%', padding: '20px' }}> <Document file={pdfUrl} onLoadSuccess={handleDocumentLoad}> <Page pageNumber={currentPage} /> </Document> <div style={{ marginTop: '10px' }}> <p>第 {currentPage} 页 / 共 {totalPages} 页</p> <button disabled={currentPage <= 1} onClick={() => setCurrentPage(prev => prev - 1)} style={{ marginRight: '10px' }} > 上一页 </button> <button disabled={currentPage >= totalPages} onClick={() => setCurrentPage(prev => prev + 1)} > 下一页 </button> </div> </div> ); } export default AdvancedPdfViewer;
为什么之前的object标签不行?
主要有两个原因:
- 后端返回的PDF数据因为没设置
responseType被损坏了,浏览器无法解析 - 直接使用后端URL时,部分浏览器对响应头的处理有差异,导致无法正确渲染PDF内容
按照上面的步骤修改后,应该就能正常显示PDF啦!
备注:内容来源于stack exchange,提问作者Hitendra singh
相关产品推荐
相关产品推荐

