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

Node.js POST请求异常:ERR_HTTP_HEADERS_SENT及响应问题

解决WhatsApp API项目POST请求异常及ERR_HTTP_HEADERS_SENT错误

问题背景

开发基于WhatsApp API的项目,从机器人功能扩展为支持人工客服的前端系统,部署在fly.io上:

  • GET请求正常返回结果
  • POST请求存在异常:用Postman发送POST请求到https://----.fly.dev/whatsapp/api/sendmessage时,WhatsApp能收到消息,但触发ERR_HTTP_HEADERS_SENT错误,服务进程退出
  • 浏览器访问https://----.fly.dev/whatsapp/messages无数据,直接访问POST路由提示Cannot GET /whatsapp/api/sendmessage

相关代码如下:

前端发送请求代码

async function sendTextFront(textResponse, number){ 
    const data = JSON.stringify({
        "messaging_product": "whatsapp",    
        "recipient_type": "individual",
        "to": number,
        "type": "text",
        "text": {
            "preview_url": true,
            "body": textResponse
        }
    })
    whatsappService.SendMessageWhatsApp(data);
    await makeRequest(data);
    return Promise.resolve(data);
};

async function makeRequest(data) {
    let config = {
        method: 'post',
        maxBodyLength: Infinity,
        url: 'https://***.fly.dev/whatsapp/api/sendmessage',
        headers: { 
          'Content-Type': 'application/json', 
        },
        data : data
      };
    try {
        const response = await axios.request(config);
        console.log(JSON.stringify(response.data));
    }
    catch (e) {
        console.log(e);
    }
}

后端路由配置

.post(`/api/sendmessage`, (req, res) => {
    const dat = whatsappController.send(req, res)
    if (dat) {
        res.status(200).json({
            success: true,
            data: datos,
        });
    } else {
        res.status(500).json({
            success: false,
            error: "Error to send the message",
        });
        console.log(dat);
    }
})

后端入口文件配置

const appname = process.env.FLY_APP_NAME;
const app = express();
const PORT = process.env.PORT || 8080
const HOST = "0.0.0.0";
app.use(express.json());
app.use("/whatsapp", apiRoute);
app.listen(PORT, HOST, () => (console.log(`Server listen in port: ${PORT} and Host in: ${HOST}`)));
console.log(`Back end in: https://${appname}.fly.dev/whatsapp/messages`);

fly.io错误日志

gru [info] node:internal/errors:491
gru [info] ErrorCaptureStackTrace(err);
gru [info] ^
gru [info] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
gru [info] at new NodeError (node:internal/errors:400:5)
gru [info] at ServerResponse.setHeader (node:_http_outgoing:663:11)
gru [info] at ServerResponse.header (/app/node_modules/express/lib/response.js:794:10)
gru [info] at ServerResponse.send (/app/node_modules/express/lib/response.js:174:12)
gru [info] at ServerResponse.json (/app/node_modules/express/lib/response.js:278:15)
gru [info] at Object.send (/app/src/controllers/whatsappControllers.js:81:25)
gru [info] at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
gru [info] code: 'ERR_HTTP_HEADERS_SENT'
gru [info] }
gru [info] Node.js v18.13.0
gru [info] INFO Main child exited normally with code: 1
gru [info] INFO Starting clean up.
gru [info] WARN hallpass exited, pid: 238, status: signal: 15 (SIGTERM)

错误原因分析

  1. ERR_HTTP_HEADERS_SENT核心原因:代码中重复发送HTTP响应。具体是whatsappController.send(req, res)方法可能已经调用res.json()或res.send()发送了响应,之后路由又再次调用res.status().json(),尝试给同一个请求发送第二次响应,触发Node.js错误。
  2. 路由异步处理错误:如果whatsappController.send是异步函数,直接赋值给dat会得到Promise对象而非实际返回值,导致if (dat)判断逻辑失效,加剧重复响应问题。
  3. 其他问题:
    • makeRequest中传递的data是手动JSON.stringify后的字符串,配合Content-Type: application/json会导致axios重复序列化,可能引发格式异常。
    • 浏览器直接访问POST路由提示Cannot GET是正常行为,该路由仅支持POST请求。
    • /whatsapp/messages无数据需检查对应GET路由的实现(未提供该部分代码)。

修复步骤

1. 修复后端路由的异步处理与重复响应

修改路由为异步函数,确保只发送一次响应:

.post(`/api/sendmessage`, async (req, res) => {
    try {
        // 假设控制器send方法返回处理后的数据,由路由统一发送响应
        const dat = await whatsappController.send(req);
        res.status(200).json({
            success: true,
            data: dat, // 修正原代码拼写错误:datos -> dat
        });
    } catch (error) {
        res.status(500).json({
            success: false,
            error: "Error to send the message",
        });
        console.error(error);
    }
})

2. 调整控制器send方法

二选一:要么返回数据由路由发送响应,要么自己发送响应但不再让路由处理。

方案一:控制器返回数据,路由处理响应

// whatsappControllers.js中的send方法
async function send(req) {
    const result = await whatsappService.SendMessageWhatsApp(req.body);
    return result;
}

方案二:控制器直接发送响应

// 路由简化为
.post(`/api/sendmessage`, (req, res) => {
    whatsappController.send(req, res);
})

// 控制器send方法
async function send(req, res) {
    try {
        const result = await whatsappService.SendMessageWhatsApp(req.body);
        res.status(200).json({ success: true, data: result });
    } catch (error) {
        res.status(500).json({ success: false, error: "Error to send the message" });
        console.error(error);
    }
}

3. 修复前端数据序列化问题

去掉手动JSON.stringify,直接传递对象,axios会自动处理序列化:

async function sendTextFront(textResponse, number){ 
    const data = {
        "messaging_product": "whatsapp",    
        "recipient_type": "individual",
        "to": number,
        "type": "text",
        "text": {
            "preview_url": true,
            "body": textResponse
        }
    };
    // 注意:原代码同时调用两个发送方法会导致重复发消息,按需保留一个
    // whatsappService.SendMessageWhatsApp(data);
    await makeRequest(data);
    return data;
};

async function makeRequest(data) {
    let config = {
        method: 'post',
        maxBodyLength: Infinity,
        url: 'https://***.fly.dev/whatsapp/api/sendmessage',
        headers: { 
          'Content-Type': 'application/json', 
        },
        data : data
      };
    try {
        const response = await axios.request(config);
        console.log(JSON.stringify(response.data));
    }
    catch (e) {
        console.error(e);
    }
}

4. 排查/whatsapp/messages无数据问题

检查对应GET路由的控制器:

  • 确保正确查询并返回数据
  • 确保调用res.json()发送响应
  • 查看fly.io日志中该路由的报错信息

额外说明

  • 浏览器直接访问POST路由提示Cannot GET是正常行为,若需支持GET请求,需添加对应路由配置。
  • 修复后重新部署到fly.io,确认日志中无ERR_HTTP_HEADERS_SENT错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:34:50