两台Node.js服务间传zip上传Express(multer)后损坏问题求助
问题根因
zipDirectory是异步操作,调用后未等待压缩完成就直接读取zip文件,此时压缩包还未完全写入磁盘,读取到的是残缺文件,这是压缩包损坏的核心原因。- 代码逻辑冗余:使用了
fs.readFile读取文件内容,但实际未用到读取结果,反而又创建了createReadStream,无实际意义。 - axios的
then回调参数写反:then第一个入参是成功响应对象,第二个才是错误对象,原逻辑会导致上传成功时也抛出错误,触发后续文件删除逻辑,导致本地原始压缩包被提前删掉,所以本地打开也会报错。 - 服务端2的上传接口未返回任何响应,axios请求会超时抛错,同样会触发错误逻辑,导致本地文件被误删。
- 扩展名提取逻辑存在缺陷:如果原始文件名包含多个
.(比如backup.v2.zip),按split('.')[1]取到的不是zip后缀,会导致保存的文件扩展名错误,无法正常识别为压缩包。 - 原代码中使用
unlinkSync删除目录是错误的,unlinkSync仅能删除文件,删除目录需要用支持递归的方法。
修复代码
服务端1代码
// 等待zip压缩完成,若zipDirectory为callback形式,先包装为Promise await new Promise((resolve, reject) => { zipDirectory( `C:/Users/${config.usuario}/Backup/`, `C:/Users/${config.usuario}/backup.zip`, (err) => err ? reject(err) : resolve() ); }); const nbackup = uuidv4(); const form = new FormData(); // 直接追加文件流,不需要提前readFile form.append("arquivo", fs.createReadStream(`C:/Users/${config.usuario}/backup.zip`)); try { const res = await axios.post( `${config.api}/backup?chave=${process.env.CHAVE}&vps=${config.vps}&id=${nbackup}`, form, { headers: { ...form.getHeaders() } } ); if (res.status === 200) { fs.unlinkSync(`C:/Users/${config.usuario}/backup.zip`); // 使用rmSync递归删除目录 fs.rmSync(`C:/Users/${config.usuario}/Backup`, { recursive: true, force: true }); } } catch (err) { console.log('上传失败', err); }
服务端2代码
const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "uploads/"); }, filename: function (req, file, cb) { // 正确提取扩展名,取最后一个.后的内容 const extensaoArquivo = file.originalname.split('.').pop(); const novoNomeArquivo = require("crypto").randomBytes(64).toString("hex"); cb(null, `${novoNomeArquivo}.${extensaoArquivo}`); } }); const upload = multer({ storage: storage }); app.post("/api/backup", upload.single("arquivo"), (req, res) => { console.log("文件接收完成"); // 返回响应避免axios超时 res.status(200).send({ status: 'success' }); });
额外优化建议
- 上传前先计算本地zip文件的MD5值,上传完成后服务端也计算接收文件的MD5,两者一致再确认上传成功,避免传输过程中损坏。
- 不要在上传流程中直接删除本地原始文件,可以添加错误重试逻辑,多次失败后再告警处理。
内容的提问来源于stack exchange,提问作者Reis
相关产品推荐
相关产品推荐

