写入文件至templates目录后生成Zip流时网络错误的解决问询
这问题我太熟了!核心就是fs.writeFile是异步非阻塞操作——你调用它之后,代码会立刻往下执行压缩逻辑,但这时候文件还没写完呢,压缩包自然会出问题,导致下载时的网络错误。
给你几个实用的解决思路,按推荐程度排序:
1. 用async/await + Promise化(最推荐,异步不阻塞)
Node.js的util.promisify可以把传统的回调式API转成Promise,配合async/await就能轻松实现顺序执行。
先改造你的控制器代码:
const util = require('util'); const fs = require('fs'); // 把fs.writeFile转成返回Promise的函数 const writeFile = util.promisify(fs.writeFile); exports.download_one_fee = async (req, res) => { try { // 等待文件写入完成,替换成你的ArrayString内容 await writeFile('./templates/目标文件名', 你的ArrayString数据); // 现在文件已经写完了,放心执行压缩流式输出 // 假设你的压缩函数是zipTemplatesDir,若它也是异步的记得加await await zipTemplatesDir(res); // 按需结束响应(如果压缩流自身会处理结束,这步可省略) res.end(); } catch (err) { console.error('文件写入失败:', err); res.status(500).send('生成文件失败,请重试'); } };
如果需要写入多个文件,就用Promise.all批量等待所有写入完成:
await Promise.all([ writeFile('./templates/file1.txt', 内容1), writeFile('./templates/file2.txt', 内容2) ]); // 所有文件写完后再执行压缩
2. 用回调嵌套(传统异步写法)
如果你不想用async/await,也可以把压缩逻辑直接放到fs.writeFile的回调里,确保只有写入成功后才执行:
exports.download_one_fee = (req, res) => { fs.writeFile('./templates/目标文件名', 你的ArrayString数据, (err) => { if (err) { console.error(err); return res.status(500).send('写入文件失败'); } // 写入成功后才启动压缩 zipTemplatesDir(res, (zipErr) => { if (zipErr) { res.status(500).send('压缩失败'); } else { res.end(); } }); }); };
3. 同步写入(不推荐,仅适合低并发场景)
用fs.writeFileSync替代fs.writeFile,它会阻塞事件循环直到文件写完,实现简单但高并发下会拖慢服务器性能:
exports.download_one_fee = (req, res) => { try { fs.writeFileSync('./templates/目标文件名', 你的ArrayString数据); zipTemplatesDir(res); } catch (err) { console.error(err); res.status(500).send('操作失败'); } };
额外提醒:如果你的压缩是用archiver这类流式库,要确保监听好流的finish事件,再结束响应,比如把压缩函数封装成Promise:
function zipTemplatesDir(res) { return new Promise((resolve, reject) => { const archive = archiver('zip'); archive.pipe(res); archive.directory('./templates', false); archive.finalize(); archive.on('finish', () => resolve()); archive.on('error', (err) => reject(err)); }); }
这样用await就能正确等待压缩流完成,避免提前结束响应。
内容的提问来源于stack exchange,提问作者alt-rock
相关产品推荐
相关产品推荐

