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

ExpressJS+MQTT接口重复请求触发ERR_HTTP_HEADERS_SENT报错求助

解决ExpressJS API中ERR_HTTP_HEADERS_SENT错误及MQTT消息重复监听问题

问题根源

你的代码在每次PUT /command请求时,都会给MQTT客户端新增一个message事件监听器。首次请求时能正常工作,但后续请求会累积多个监听器——当MQTT服务器返回消息时,所有累积的监听器都会触发,每个都尝试调用res.send(),导致重复发送HTTP响应头,最终抛出ERR_HTTP_HEADERS_SENT错误。此外,订阅hwid后未取消订阅,会导致客户端持续接收该主题的无关消息,进一步干扰后续请求。

修改后的代码

const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const mqtt = require("mqtt");
const client = mqtt.connect("serverip");

client.on("connect", function () {
  console.log("[API]: Successfully connected to the server");
});

app.use(bodyParser.json());

app.put("/command", (req, res) => {
  const { hwid, command } = req.body;
  console.log(`PUT method request for: ${hwid}`);

  // 定义命名的消息处理回调,方便后续移除
  function handleMessage(topic, message) {
    const messageStr = message.toString();
    // 过滤自身发送的命令消息
    if (messageStr === command) return;
    // 仅处理当前请求对应hwid的响应
    if (topic !== hwid) return;

    // 返回响应给客户端
    res.send({ hwid: topic, content: messageStr });
    // 移除当前请求的消息监听器,避免累积
    client.off("message", handleMessage);
    // 取消订阅该hwid主题,清理资源
    client.unsubscribe(hwid);
  }

  // 绑定消息监听器
  client.on("message", handleMessage);

  client.subscribe(hwid, function (err) {
    if (err) {
      // 订阅失败时先清理监听器,再返回错误
      client.off("message", handleMessage);
      return res.status(500).send({ error: "Failed to publish command" });
    }
    // 订阅成功后发布命令
    client.publish(hwid, command);
  });

  // 设置超时,防止MQTT无响应导致请求挂起
  const timeoutTimer = setTimeout(() => {
    client.off("message", handleMessage);
    client.unsubscribe(hwid);
    res.status(408).send({ error: "Request timeout: No response from target device" });
  }, 10000); // 10秒超时,可根据需求调整

  // 响应发送完成后清除超时定时器
  res.on("finish", () => clearTimeout(timeoutTimer));
});

app.listen(3000, () => {
  console.log("Server started on port 3000");
});

关键改动说明

  1. 避免监听器累积:使用命名回调函数handleMessage,在请求处理完成(收到响应或超时)后,通过client.off()移除该监听器,确保每个请求仅对应一个回调。
  2. 清理订阅资源:收到响应或超时后,取消对当前hwid的订阅,避免客户端持续接收无关消息。
  3. 添加超时保护:防止MQTT长时间无响应导致HTTP请求挂起,提升API健壮性。
  4. 严格响应匹配:增加topic === hwid判断,确保仅处理当前请求对应的目标设备响应,避免其他设备消息干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:43:12