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

Node.js实现服务器存储Excel文件下载API遇问题求助

问题:Excel文件下载API在Postman中无法正常工作

我已将Excel文件直接存储在服务器中,上传API功能正常,但开发的下载选中文件的API在Postman中无法正常运行,相关源码如下:

路由代码

router.get(
  "/downloadExcel/:id",
  postController.downloadExcel
);

控制器代码

exports.downloadExcel = async (req: Request, res: Response) => {
  try {    
    const post= await Post.findById(req.params.id);

    let fileName: string = post.newExcelPath.replace(
      "/utilities/uploaded-excels/",
      ""
    );

    res.setHeader(
      "Content-Type",
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    );
    res.setHeader("Content-Disposition", "attachment; filename=" + fileName);

    let dirname: string = __dirname.replace("/controllers", "");

    const fileStream = fs
      .createWriteStream(dirname + post.newExcelPath)
      .on("error", (error: any) => console.log(error))
      .on("finish", () => {
        res.download(dirname + "/utilities/uploaded-excels/" + fileName);    
        res.status(200).json(post);
      });
  } catch (err) {
    res.status(404).json({ success: false, msg: err });
  }
};

问题分析与修复方案

核心问题点

  1. 流类型错误:使用createWriteStream(写入流)而非createReadStream(读取流),根本没有读取服务器上的目标文件内容。
  2. 重复响应:res.download会自动完成响应发送,后续的res.status(200).json(post)会触发"Cannot set headers after they are sent to the client"错误。
  3. 路径处理不严谨:直接用字符串替换处理路径,容易因操作系统路径分隔符差异导致文件找不到。

修正后的控制器代码

const path = require('path'); // 引入path模块处理路径

exports.downloadExcel = async (req: Request, res: Response) => {
  try {    
    const post = await Post.findById(req.params.id);
    if (!post) {
      return res.status(404).json({ success: false, msg: "文件记录不存在" });
    }

    // 用path模块拼接绝对路径,避免跨系统路径问题
    const filePath = path.join(__dirname, '..', post.newExcelPath);
    const fileName = path.basename(filePath); // 直接提取文件名,更可靠

    // res.download会自动设置正确的Content-Type和Content-Disposition,无需手动设置
    res.download(filePath, fileName, (err) => {
      if (err) {
        console.error(err);
        res.status(500).json({ success: false, msg: "文件下载失败" });
      }
    });
  } catch (err) {
    res.status(500).json({ success: false, msg: err.message || "服务器错误" });
  }
};

Postman测试注意事项

发送GET请求时,不要用普通的"Send"按钮,选择**"Send and Download"**选项,Postman才会识别并触发文件下载操作,而不是直接显示响应内容。

内容的提问来源于stack exchange,提问作者devZ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:05:26