Express后端用sendFile返回文件,React前端如何处理该响应?
Got it, let's break down how to handle that file response from your Express backend in React. That locked: true ReadableStream you're seeing is totally expected—here's what's happening and how to properly process the file:
Why You're Seeing a Locked ReadableStream
When your Express server sends a file via sendFile, the browser returns the content as a readable stream. If you try to log the raw response body directly, or if you've already attempted to read the stream (even implicitly), it gets "locked" and can't be read again. Instead, we need to convert that stream into a Blob (binary large object) which we can work with for downloads or previews.
Solution 1: Using the Fetch API
Here's how to fetch the file and trigger a download in React:
const downloadFile = async (productFileName) => { try { const response = await fetch(`/your-express-route/${productFileName}`); // Convert the stream to a Blob const blob = await response.blob(); // Create a temporary URL for the Blob const url = window.URL.createObjectURL(blob); // Create an invisible <a> tag to trigger download const a = document.createElement('a'); a.href = url; // Set the filename for the downloaded file a.download = productFileName; document.body.appendChild(a); a.click(); // Clean up: revoke the URL and remove the <a> tag window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (error) { console.error('Error downloading file:', error); } };
Solution 2: Using Axios
If you're using Axios instead of fetch, make sure to set responseType: 'blob' in your request config—this tells Axios to handle the response as binary data:
import axios from 'axios'; const downloadFile = async (productFileName) => { try { const response = await axios.get(`/your-express-route/${productFileName}`, { responseType: 'blob' // Critical for handling binary files }); const url = window.URL.createObjectURL(new Blob([response.data])); const a = document.createElement('a'); a.href = url; a.download = productFileName; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (error) { console.error('Error downloading file:', error); } };
Bonus: Previewing the File (e.g., Images/PDFs)
If you want to preview the file instead of downloading it (like showing an image or PDF), you can use the Blob URL directly in an <img> or <iframe> tag:
import { useState, useEffect } from 'react'; const FilePreview = ({ productFileName }) => { const [fileUrl, setFileUrl] = useState(null); const loadFilePreview = async () => { try { const response = await fetch(`/your-express-route/${productFileName}`); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); setFileUrl(url); } catch (error) { console.error('Error loading file preview:', error); } }; // Clean up the Blob URL when component unmounts useEffect(() => { return () => { if (fileUrl) { window.URL.revokeObjectURL(fileUrl); } }; }, [fileUrl]); return ( <div> <button onClick={loadFilePreview}>Load Preview</button> {fileUrl && <img src={fileUrl} alt="Product file preview" style={{ maxWidth: '100%' }} />} {/* For PDFs, use an iframe instead: */} {/* {fileUrl && <iframe src={fileUrl} title="PDF Preview" width="100%" height="500px" />} */} </div> ); };
内容的提问来源于stack exchange,提问作者Javad Sameri

