使用React JS无法下载MongoDB中二进制存储的PDF文件
问题:PDF上传MongoDB后前端下载失败+无限循环下载
现象说明
- 使用
express-fileupload将PDF文件上传至MongoDB后,前端下载打开时提示「Error. Failed to load PDF document」 - 点击下载按钮会触发无限循环下载的情况
MongoDB存储的数据结构
_id: ObjectId('63b7494295b850d0452a6a81') username: "sita" email: "sita@gmail.com" dob: 2023-01-01T00:00:00.000+00:00 city: "city" address: "add" services: Array 0: "Demat" pancard: Object Data:BinData(0,'JVBERi0xLjcKCjQgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAzMDEzNQo+PgpzdHJlYW0KeJztvU1247gS…') ContentType: "application/pdf" createdAt: 2023-01-05T22:03:46.893+00:00 updatedAt: 2023-01-05T22:03:46.893+00:00 __v: 0
前端React代码
React.useEffect(()=>{ const fetchClient = async () =>{ const res = await axios.get('/users/sita@gmail.com'); setData(res.data.pancard.Data.data); setContentType(res.data.pancard.contentType) } fetchClient() },[userdetail]); const downloadPdf = (filename, contentType) => { const file = new Blob([data], { type: contentType }); saveAs(file, "pancard.pdf") //const fileURL = URL.createObjectURL(file); //window.open(fileURL); };
JSX中的按钮调用
<button class="btn btn-primary button" onClick={downloadPdf('pancard', contentType)}>Download</button>
问题修复方案
1. 解决无限循环下载问题
当前按钮的onClick直接执行了downloadPdf()函数,导致组件渲染时就会触发下载,结合useEffect的依赖更新,形成无限循环。
修复代码:
将onClick改为箭头函数,仅在点击时触发下载;同时React中需用className替代class:
<button className="btn btn-primary button" onClick={() => downloadPdf('pancard', contentType)}>Download</button>
2. 解决PDF无法打开问题
MongoDB中存储的BinData是Base64编码的二进制数据,前端直接用返回的字符串创建Blob会导致文件损坏,需要先解码为二进制数组。
修复代码:
第一步:修改数据获取逻辑
React.useEffect(()=>{ const fetchClient = async () =>{ const res = await axios.get('/users/sita@gmail.com'); // 注意MongoDB字段是ContentType(大写C),需与接口返回字段匹配 setContentType(res.data.pancard.ContentType); // 解码Base64字符串为Uint8Array二进制数组 const base64Str = res.data.pancard.Data; const binaryStr = atob(base64Str); const bytes = new Uint8Array(binaryStr.length); for (let i = 0; i < binaryStr.length; i++) { bytes[i] = binaryStr.charCodeAt(i); } setData(bytes); } fetchClient() },[userdetail]);
第二步:完善下载函数(增加空值判断)
const downloadPdf = (filename, contentType) => { // 避免数据未加载完成时触发下载 if (!data || !contentType) return; const file = new Blob([data], { type: contentType }); saveAs(file, `${filename}.pdf`); };
内容的提问来源于stack exchange,提问作者GAURI WALKE
相关产品推荐
相关产品推荐

