如何在React.js中解析REST API响应并利用字节数据生成PDF
First, let’s break down what we’re working with: your API returns an XML response where the <PDFContent> tag holds a base64-encoded string of the PDF file. Here’s a step-by-step guide to extract this content and render/download the PDF in React:
Step 1: Parse the XML Response to Get Base64 Data
Since the response is in XML format, we’ll use the browser’s built-in DOMParser to extract the base64 string from the <PDFContent> tag.
const parseXmlResponse = (responseText) => { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(responseText, "application/xml"); const pdfContentElement = xmlDoc.querySelector("PDFContent"); return pdfContentElement ? pdfContentElement.textContent : null; };
Step 2: Convert Base64 String to a Blob
Base64 is a text-based representation of binary data—we need to convert it to a Blob (binary large object) to treat it as a proper PDF file.
const base64ToBlob = (base64String) => { // Decode base64 to binary string const binaryString = atob(base64String); // Convert binary string to Uint8Array const uint8Array = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { uint8Array[i] = binaryString.charCodeAt(i); } // Return Blob with PDF MIME type return new Blob([uint8Array], { type: "application/pdf" }); };
Step 3: Render the PDF in React
You have two straightforward options to display the PDF in your component: using an <iframe> (simple) or the react-pdf library (for more control).
Option A: Using an Iframe (Quick & Simple)
This is the easiest way to render the PDF without extra dependencies:
import { useState, useEffect } from "react"; const PdfViewer = ({ apiResponse }) => { const [pdfUrl, setPdfUrl] = useState(null); useEffect(() => { if (!apiResponse) return; // Extract base64 from XML const base64Data = parseXmlResponse(apiResponse); if (!base64Data) return; // Convert to Blob and create object URL const pdfBlob = base64ToBlob(base64Data); const url = URL.createObjectURL(pdfBlob); setPdfUrl(url); // Cleanup: Revoke URL to free memory when component unmounts return () => { if (url) URL.revokeObjectURL(url); }; }, [apiResponse]); if (!pdfUrl) return <div>Loading PDF...</div>; return ( <iframe src={pdfUrl} title="PDF Viewer" style={{ width: "100%", height: "80vh", border: "none" }} /> ); };
Option B: Using react-pdf (Customizable)
For features like pagination or custom styling, use the react-pdf library. First install it:
npm install @react-pdf/renderer
Then create a component to render the PDF:
import { useState, useEffect } from "react"; import { Document, Page, pdfjs } from "@react-pdf/renderer"; // Configure PDF.js worker (required for react-pdf) pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`; const PdfViewer = ({ apiResponse }) => { const [pdfDocument, setPdfDocument] = useState(null); const [numPages, setNumPages] = useState(0); useEffect(() => { if (!apiResponse) return; const base64Data = parseXmlResponse(apiResponse); if (!base64Data) return; // Convert base64 to ArrayBuffer for pdfjs const binaryString = atob(base64Data); const arrayBuffer = new ArrayBuffer(binaryString.length); const uint8Array = new Uint8Array(arrayBuffer); for (let i = 0; i < binaryString.length; i++) { uint8Array[i] = binaryString.charCodeAt(i); } // Load PDF document pdfjs.getDocument(arrayBuffer).promise.then((doc) => { setPdfDocument(doc); setNumPages(doc.numPages); }); }, [apiResponse]); if (!pdfDocument) return <div>Loading PDF...</div>; return ( <div style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }}> {Array.from({ length: numPages }, (_, i) => i + 1).map((pageNumber) => ( <Document key={pageNumber} file={pdfDocument}> <Page pageNumber={pageNumber} style={{ margin: "1rem 0" }} /> </Document> ))} </div> ); };
Step 4: Add a Download Button
Let users download the PDF by creating a temporary download link from the Blob:
const PdfDownloadButton = ({ apiResponse }) => { const handleDownload = () => { if (!apiResponse) return; const base64Data = parseXmlResponse(apiResponse); if (!base64Data) return; const pdfBlob = base64ToBlob(base64Data); const url = URL.createObjectURL(pdfBlob); // Create anchor tag and trigger download const a = document.createElement("a"); a.href = url; a.download = "my-document.pdf"; // Set your desired filename document.body.appendChild(a); a.click(); document.body.removeChild(a); // Cleanup object URL URL.revokeObjectURL(url); }; return <button onClick={handleDownload} style={{ padding: "0.5rem 1rem" }}>Download PDF</button>; };
Putting It All Together
Combine these components in your main app to fetch, render, and let users download the PDF:
const App = () => { const [apiResponse, setApiResponse] = useState(null); useEffect(() => { // Example fetch call to your API fetch("your-api-endpoint") .then((res) => res.text()) // Get response as text (since it's XML) .then((text) => setApiResponse(text)) .catch((err) => console.error("Fetch error:", err)); }, []); if (!apiResponse) return <div>Fetching data...</div>; return ( <div style={{ padding: "2rem" }}> <h1>PDF Viewer & Download</h1> <PdfViewer apiResponse={apiResponse} /> <div style={{ marginTop: "1rem" }}> <PdfDownloadButton apiResponse={apiResponse} /> </div> </div> ); }; export default App;
Key Tips
- Memory Cleanup: Always revoke object URLs with
URL.revokeObjectURL()after use to avoid memory leaks. - Error Handling: Add checks for cases where XML parsing fails or the base64 string is invalid.
- CORS: Ensure your API allows cross-origin requests if your React app is hosted on a different domain.
内容的提问来源于stack exchange,提问作者kinnu

