Node.js向客户端发送文件挂起,仅服务器终止后完成传输问题排查
问题分析与解决方案
我来帮你排查这个下载卡住的问题,从你给出的代码片段来看,主要有几个关键问题导致了这个现象:
1. Content-Length 头设置错误
你现在用fs.statSync(filePath)直接作为Content-Length的值,但这个方法返回的是一个Stats对象,不是文件的字节大小。浏览器无法解析这个错误的长度值,就会一直等待服务器传输数据,导致进度卡在“正在启动”阶段,直到服务器终止才被迫完成下载。
正确的做法是获取Stats对象的size属性:
res.setHeader('Content-Length', fs.statSync(filePath).size);
2. 缺少必要的响应头
你代码里的Content-...看起来没写完,浏览器需要明确的Content-Type和Content-Disposition头来识别这是一个可下载的CSV文件,否则可能无法正确触发下载流程:
res.setHeader('Content-Type', 'text/csv'); res.setHeader('Content-Disposition', 'attachment; filename="weather_log.csv"');
3. 未正确结束响应
你用fs.readFileSync读取了文件内容,但如果没有把数据发送给客户端并结束响应,服务器会一直保持HTTP连接,浏览器就会一直处于等待状态。正确的流程是读取文件后,写入响应并结束:
var file = fs.readFileSync(filePath, 'binary'); res.write(file, 'binary'); res.end();
修正后的完整代码示例
const fs = require('fs'); // 假设app是express实例 app.get('/weather_log.csv', function(req, res){ console.log('sending weather log'); const filePath = 'weather_log.csv'; try { // 获取文件信息,确保文件存在 const stats = fs.statSync(filePath); // 设置响应头 res.setHeader('Content-Length', stats.size); res.setHeader('Content-Type', 'text/csv'); res.setHeader('Content-Disposition', 'attachment; filename="weather_log.csv"'); // 读取并发送文件 const file = fs.readFileSync(filePath, 'binary'); res.write(file, 'binary'); res.end(); } catch (err) { // 处理文件不存在等错误 res.status(404).send('File not found'); console.error(err); } });
另外,其实更推荐用Express的res.download()方法,它会自动处理这些响应头和文件发送逻辑,代码更简洁也不容易出错:
app.get('/weather_log.csv', function(req, res){ console.log('sending weather log'); const filePath = 'weather_log.csv'; res.download(filePath, 'weather_log.csv', function(err) { if (err) { console.error(err); res.status(404).send('File not found'); } }); });
内容的提问来源于stack exchange,提问作者Daniel Paczuski Bak
相关产品推荐
相关产品推荐

