You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 22:36:05