如何在React中查看从Node.js后端传来的PDF Array Buffer?
React中查看后端加密传输的PDF文件
首先你需要在前端完成解密操作——因为后端用encryptionOfData加密了响应数据,前端必须用对应的decryptionOfData函数解密,才能拿到原始的PDF二进制数据。
步骤1:前端请求并解密数据
假设你用axios发送请求(用fetch逻辑类似),拿到加密响应后先解密:
import axios from 'axios'; // 前端实现与后端匹配的解密函数 const decryptionOfData = (encryptedData) => { // 这里写对应后端加密逻辑的解密代码,比如AES对称解密 // 解密后返回原始PDF二进制数据(Uint8Array/ArrayBuffer类型) }; const fetchAndPreviewPDF = async (username) => { try { // 必须指定响应类型为arraybuffer,防止二进制数据乱码 const response = await axios.get(`/api/get-certificate?username=${username}`, { responseType: 'arraybuffer' }); // 解密得到原始PDF数据 const decryptedPDFData = decryptionOfData(response.data); // 进入预览处理环节 handlePDFPreview(decryptedPDFData); } catch (error) { console.error('获取/解密PDF失败:', error); } };
步骤2:将解密后的数据转为Blob
浏览器处理PDF需要Blob对象,先完成格式转换:
const handlePDFPreview = (pdfData) => { const pdfBlob = new Blob([pdfData], { type: 'application/pdf' }); // 选择以下任意一种方式实现预览 };
方式1:用iframe快速预览
适合简单场景,直接在页面嵌入iframe展示:
const handlePDFPreview = (pdfData) => { const pdfBlob = new Blob([pdfData], { type: 'application/pdf' }); const blobUrl = URL.createObjectURL(pdfBlob); // 动态创建iframe插入页面 const iframe = document.createElement('iframe'); iframe.src = blobUrl; iframe.width = '100%'; iframe.height = '800px'; document.getElementById('pdf-container').appendChild(iframe); // 页面卸载时释放Blob URL,避免内存泄漏 window.addEventListener('beforeunload', () => { URL.revokeObjectURL(blobUrl); }); };
React组件内也可直接写JSX:
const PDFViewer = ({ pdfBlobUrl }) => { return ( <div id="pdf-container"> {pdfBlobUrl && <iframe src={pdfBlobUrl} width="100%" height="800px" title="PDF预览" />} </div> ); };
方式2:用PDF.js自定义渲染(支持分页/样式定制)
如果需要更灵活的控制(比如分页、自定义样式),可以用官方pdfjs-dist库:
- 先安装依赖:
npm install pdfjs-dist
- 组件示例:
import { useState, useEffect } from 'react'; import * as pdfjsLib from 'pdfjs-dist'; import 'pdfjs-dist/build/pdf.worker.entry'; // 设置PDF.js的worker路径 pdfjsLib.GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; const CustomPDFViewer = ({ pdfData }) => { const [pdfDoc, setPdfDoc] = useState(null); const [currentPage, setCurrentPage] = useState(1); useEffect(() => { const loadPDF = async () => { const pdfBlob = new Blob([pdfData], { type: 'application/pdf' }); const pdfUrl = URL.createObjectURL(pdfBlob); const doc = await pdfjsLib.getDocument(pdfUrl).promise; setPdfDoc(doc); // 页面卸载时释放URL return () => URL.revokeObjectURL(pdfUrl); }; if (pdfData) loadPDF(); }, [pdfData]); const renderCurrentPage = async () => { if (!pdfDoc) return; const page = await pdfDoc.getPage(currentPage); const canvas = document.getElementById('pdf-canvas'); const ctx = canvas.getContext('2d'); const viewport = page.getViewport({ scale: 1.5 }); canvas.height = viewport.height; canvas.width = viewport.width; await page.render({ canvasContext: ctx, viewport }).promise; }; useEffect(() => { renderCurrentPage(); }, [pdfDoc, currentPage]); return ( <div> <canvas id="pdf-canvas" /> <div style={{ marginTop: '16px' }}> <button onClick={() => setCurrentPage(p => Math.max(1, p - 1))} disabled={currentPage === 1}> 上一页 </button> <span style={{ margin: '0 16px' }}>第 {currentPage} / {pdfDoc?.numPages || 0} 页</span> <button onClick={() => setCurrentPage(p => Math.min(pdfDoc.numPages, p + 1))} disabled={currentPage === pdfDoc?.numPages}> 下一页 </button> </div> </div> ); };
方式3:生成临时链接供打开/下载
如果不需要页面内预览,可生成链接让用户在新标签页打开或下载:
const handlePDFPreview = (pdfData) => { const pdfBlob = new Blob([pdfData], { type: 'application/pdf' }); const blobUrl = URL.createObjectURL(pdfBlob); // 方式A:在新标签页打开PDF window.open(blobUrl, '_blank'); // 方式B:触发下载 const downloadBtn = document.createElement('a'); downloadBtn.href = blobUrl; downloadBtn.download = `${username}_certificate.pdf`; downloadBtn.click(); // 延迟释放Blob URL setTimeout(() => URL.revokeObjectURL(blobUrl), 1000); };
内容的提问来源于stack exchange,提问作者Manas S. Roy
相关产品推荐
相关产品推荐

