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
相关产品推荐
相关产品推荐

