Node+React图片压缩项目res.download后调用unlink删文件导致下载失败怎么解决
问题原因
- Express 内置的
res.download()属于回调风格API,不会返回Promise,你添加的await不会等待文件传输完成,会直接执行后续的删除逻辑,文件还没发送完毕就被删除,自然会触发下载失败、服务端报错的问题。 - 你的压缩文件路径拼接逻辑存在错误,
compressedImage[0].destinationPath已经是imagemin返回的完整路径,不需要手动拼接compressed/+原路径,错误的路径会导致删除文件失败。 - 你混用了
unlink的回调写法和await语法,Node.js原生fs模块的回调式API不会返回Promise,await不会生效。
解决代码
我们可以把res.download封装为Promise,等待文件完全发送后再执行删除,同时统一用fs/promises的异步API避免回调嵌套:
// 顶部先引入promise版本的unlink const { unlink } = require('fs/promises'); app.get('/download/:imageName', async (req,res)=>{ let imageName = req.params.imageName let originalPath = 'uploads/'+imageName; let compressedPath = null; try { const compressedImage = await imagemin([originalPath], { destination: "compressed", plugins: [ imageminPngquant({ quality: [0.6, 0.8] }), imageminMozjpeg(), imageminGifsicle({lossy: 70}), imageminSvgo({ plugins: extendDefaultPlugins([ {name: 'removeViewBox', active: false} ]) }) ] }); compressedPath = process.cwd()+"/"+compressedImage[0].destinationPath; // 封装res.download为Promise等待执行完成 await new Promise((resolve, reject) => { res.download(compressedPath, (err) => { if (err) return reject(err); resolve(); }); }); // 下载完成后删除文件 await unlink(compressedPath); console.log(compressedPath + " has been deleted"); } catch (err) { // 出错时如果压缩文件已生成,也要删除避免残留 if (compressedPath) { try { await unlink(compressedPath); } catch (unlinkErr) { console.error('删除压缩文件失败:', unlinkErr); } } // 给客户端返回错误响应 if (!res.headersSent) { res.status(500).send('下载失败'); } console.error('处理下载请求出错:', err); } })
替代方案:监听响应finish事件
你也可以直接监听响应对象的finish事件,该事件会在响应数据完全发送到客户端后触发:
// 下载逻辑无需await,直接调用 res.download(compressedPath); // 监听响应完成事件后删除文件 res.on('finish', async () => { try { await unlink(compressedPath); console.log(compressedPath + " has been deleted"); } catch (err) { console.error('删除文件失败:', err); } }); // 还要监听close事件处理客户端中途断开连接的场景,避免文件残留 res.on('close', async () => { try { await unlink(compressedPath); } catch (err) { console.error('删除文件失败:', err); } });
内容的提问来源于stack exchange,提问作者Iftekhar Riyad
相关产品推荐
相关产品推荐

