React前端接收NodeJS返回文件异常:文件变大无法打开
问题:前端下载的文件体积变大且无法打开
我在NodeJS应用中实现了一个API接口,通过接收前端传递的文件名,查找指定文件夹中的对应文件。后端代码如下:
const fileDirectory = 'C:/Sites/private-uploads'; try { // Extract filename from request parameters or query string const body = ctx.request.body; // Assuming filename is passed as a parameter in the route const filename = body.data.filename; // Check if the file exists const filePath = path.join(fileDirectory, filename); console.log(filePath); if (!fs.existsSync(filePath)) { ctx.status = 404; ctx.body = { error: 'File not found' }; return; } // Read the file contents as raw binary data const fileContents = await fs.readFile(filePath, null); // Passing null as the encoding parameter const fileSizeKB = fileContents.length / 1024; // Convert bytes to kilobytes console.log('File size:', fileSizeKB.toFixed(2), 'KB'); // Set appropriate headers ctx.set('Content-Type', 'application/octet-stream'); // Set Content-Type to indicate binary data ctx.set('Content-Disposition', `attachment; filename="${filename}"`); // Set filename for download // Send the file contents as the response body ctx.body = fileContents; } catch (error) { console.error(error); ctx.status = 500; ctx.body = { error: 'Error retrieving file contents' }; }
后端打印的文件大小显示正常。我的React应用中接收文件的代码如下:
const getFile = async (filename) => { try { const response = await api.post('/api/get-file', { data: { filename: filename } }); if (response.data) { console.log(response.data); const blob = new Blob([response.data]); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } } catch (error) { console.log(error); } }
但前端接收并生成的文件体积变大,且无法正常打开,请问哪里操作出错了?
问题原因及修复方案
核心原因
前端请求时未指定响应数据类型为二进制,导致请求库(默认是axios)自动将二进制数据解析为UTF-8字符串。字符串再转换为Blob时,会出现编码失真,最终造成文件损坏、体积膨胀。
1. 前端修复:指定响应类型为blob
修改请求配置,明确告诉axios返回二进制Blob对象,无需手动转换:
const getFile = async (filename) => { try { const response = await api.post('/api/get-file', { data: { filename: filename }, responseType: 'blob' // 关键配置:直接接收Blob }); if (response.data) { const url = window.URL.createObjectURL(response.data); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } } catch (error) { console.log(error); } }
2. 后端可选优化:流式传输大文件
如果涉及大文件下载,fs.readFile会将整个文件加载到内存,影响性能。建议改用流式传输:
const filePath = path.join(fileDirectory, filename); if (!fs.existsSync(filePath)) { ctx.status = 404; ctx.body = { error: 'File not found' }; return; } // 设置响应头 ctx.set('Content-Type', 'application/octet-stream'); ctx.set('Content-Disposition', `attachment; filename="${encodeURIComponent(filename)}"`); // 流式输出文件 ctx.body = fs.createReadStream(filePath);
3. 安全优化:避免文件名XSS风险
后端直接拼接文件名到响应头存在XSS风险,需对文件名进行转义:
ctx.set('Content-Disposition', `attachment; filename="${encodeURIComponent(filename)}"`);
内容的提问来源于stack exchange,提问作者Gery
相关产品推荐
相关产品推荐

