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

Node.js中'Cannot set headers after they are sent to the client'错误解决

解决ERR_HTTP_HEADERS_SENT错误,让前端可持续发起请求

错误根源

这个ERR_HTTP_HEADERS_SENT错误是因为同一个HTTP请求被多次发送响应:

  • getBooksInfo里的forEach循环,每遍历到一本符合条件的书就调用一次result回调,导致showBooks里多次执行res.json/res.send,而一个HTTP请求只能返回一次响应。
  • 同时async/await和回调混用,加上forEach不支持异步等待,导致异步流程完全失控,数据还没收集完就返回,甚至多次触发响应。

具体修复步骤

1. 重构book_api,移除回调,直接返回Promise

既然用了async/await,没必要再用回调函数,直接返回数据或抛出错误:

export const book_api = async (author_name) => {
  const response = await axios.get(`https://book-service.com?author=${author_name}`);
  const author_info = response.data.author;
  return {
    "name": author_info.name,
    "website": author_info.website
  };
};

请求失败时,async函数会自动抛出错误,后续用try/catch统一捕获。

2. 重构getBooksInfo,用Promise.all处理异步遍历

去掉回调,改用返回Promise,用for...of替代forEach(支持异步等待),并用Promise.all批量处理API请求:

export const getBooksInfo = async (books) => {
  const all_books = [];

  for (const book of books) {
    // 过滤符合条件的书籍
    if (book.type === "adventure" && book.meta.sale) {
      // 生成所有作者信息请求的Promise数组
      const authorRequests = book.meta.authors.map(author => book_api(author.name));
      // 等待所有请求完成,获取结果
      const authorsData = await Promise.all(authorRequests);
      // 将结果合并到数组
      all_books.push(...authorsData);
    }
  }

  return { input: all_books };
};

这样能确保所有异步请求完成后才返回数据,且只会返回一次结果。

3. 修复showBooks,统一处理响应

现在getBooksInfo返回Promise,直接await获取结果,只发送一次响应,同时捕获所有异常:

export const showBooks = async (req, res) => {
  try {
    const books = req.body.books;
    const results = await getBooksInfo(books);
    res.json(results);
  } catch (err) {
    console.error(err);
    res.status(500).send(err.message || "获取书籍信息失败");
  }
};

修复后效果

修改完成后,每个前端请求只会触发一次响应,异步流程也能正确等待所有API请求完成,服务不会因为重复发送响应崩溃,前端可以持续发起新请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:15:29