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

MQTT转SignalR数据接收异常:跨网络数据丢失问题排查

问题分析与修复方案

问题根源

  1. 摄像头ID全局冲突:不同网络的摄像头ID可能重复,但DOM元素(表格、图片卡片)仅用cameraId作为唯一标识,导致不同网络的数据共用同一DOM节点。切换网络时,旧网络的清除操作会清空新网络需要使用的DOM内容,而新数据因更新条件限制无法写入。
  2. 数据更新条件不合理:updateCameraTable中仅当单元格内容为'-'时才更新数据,若同一cameraId的DOM节点已被其他网络填充过数据,新网络的数据无法正常写入。
  3. 清除操作未区分网络:clearTableForCamera直接根据cameraId清除DOM内容,会误清除其他网络的同ID摄像头数据。

修复代码

1. 先调整DOM元素命名规则

确保每个网络的摄像头元素包含网络地址前缀,避免跨网络冲突:

  • 表格ID改为 tableZone${receivedAddress}_${cameraId}
  • 图片卡片ID改为 ImageCard${receivedAddress}_${cameraId}

2. 修正JavaScript代码

// Object to store unique camera IDs for each network
let uniqueCameraIds = {};

// Mapping for camera IDs to image paths
let cameraImagePaths = {};

// Object to store network-specific data
let networkData = {};

let connection = new signalR.HubConnectionBuilder()
    .withUrl("/hub/status")
    .build();

connection.start()
    .then(() => {
        console.log("SignalR connected");

        connection.on("ReceiveMessage", (message, imgPaths) => {
            console.log("Received data from SignalR:", message);

            try {
                let data = typeof message === 'string' ? JSON.parse(message) : message;
                let msgTypes = data.msg_content.split(":");

                if (msgTypes[0] === 'm') {
                    handleObjectMessage(data, imgPaths);
                } else if (msgTypes[0] === 'h') {
                    handleHeartbeatMessage(data);
                }
            } catch (error) {
                console.error("Error parsing JSON or extracting values:", error);
            }
        });
    })
    .catch((err) => {
        console.error("Error starting SignalR connection:", err.toString());
    });

function handleObjectMessage(data, imgPaths) {
    let msgContent = data.msg_content.slice(2);
    let zoneDataArray = msgContent.split('|');

    // Extract and log the address
    let receivedAddress = `${data.network_add}.${data.node_add}`;
    console.log("Received address:", receivedAddress);

    // Check if the networkData object exists for the received network
    if (!networkData[receivedAddress]) {
        console.log(`Initializing data for network: ${receivedAddress}`);
        networkData[receivedAddress] = {
            uniqueCameraIds: [],
            cameraImagePaths: {},
            isFirstTime: true // 仅初始化时为true
        };
    }

    // 仅清除当前网络自己的旧数据
    if (!networkData[receivedAddress].isFirstTime) {
        console.log(`Clearing old data for network: ${receivedAddress}`);
        clearDataForNetwork(receivedAddress);
    }

    // 保留当前网络的摄像头ID
    zoneDataArray.forEach(zoneData => {
        let cameraId = zoneData.split(',')[0];
        if (!networkData[receivedAddress].uniqueCameraIds.includes(cameraId)) {
            networkData[receivedAddress].uniqueCameraIds.push(cameraId);
        }
    });

    // 存储当前网络的摄像头图片路径
    imgPaths.forEach(imgPath => {
        Object.keys(imgPath).forEach(cameraId => {
            networkData[receivedAddress].cameraImagePaths[cameraId] = imgPath[cameraId];
        });
    });

    // 更新状态
    networkData[receivedAddress].isFirstTime = false;

    // 更新摄像头表格(仅当对应的DOM存在时)
    let dashboardElement = document.getElementById(`dashboard${receivedAddress}`);
    if (dashboardElement !== null) {
        console.log(`Received address ${receivedAddress} exists in the HTML model.`);
        updateCameraTable(zoneDataArray, data, receivedAddress);
    } else {
        console.warn(`Received address ${receivedAddress} has no matching dashboard element.`);
    }
}

function clearDataForNetwork(networkAddress) {
    networkData[networkAddress].uniqueCameraIds.forEach((cameraId) => {
        clearTableForCamera(networkAddress, cameraId);
    });

    // 重置当前网络的数据存储
    networkData[networkAddress].uniqueCameraIds = [];
    networkData[networkAddress].cameraImagePaths = {};
}

function updateCameraTable(zoneDataArray, data, receivedAddress) {
    zoneDataArray.forEach((zoneData) => {
        let values = zoneData.split(',');

        let cameraId = values[0];
        let zoneId = values[1];
        let peopleCount = values[2];
        let carCount = values[3];
        let truckCount = values[4];
        let motorcycleCount = values[5];
        let miscCount = values[6];

        console.log("Extracted values:", receivedAddress, data.msg_id, cameraId, zoneId, peopleCount, carCount, truckCount, motorcycleCount, miscCount);

        if (!cameraId) {
            console.error("Camera ID is missing.");
            return;
        }

        let formattedZoneId = `Zone${zoneId.replace('|', '_')}`;
        // 使用带网络地址的表格选择器
        let tableCell = $(`#tableZone${receivedAddress}_${cameraId} [data-zone="${formattedZoneId}"]`);

        // 每次收到数据都更新,移除仅当内容为'-'才更新的限制
        tableCell.find('.people').text(` ${peopleCount}`);
        tableCell.find('.car').text(` ${carCount}`);
        tableCell.find('.truck').text(` ${truckCount}`);
        tableCell.find('.bike').text(` ${motorcycleCount}`);
        tableCell.find('.misc').text(` ${miscCount}`);

        // 使用带网络地址的图片卡片选择器
        if (networkData[receivedAddress].cameraImagePaths[cameraId]) {
            $(`#ImageCard${receivedAddress}_${cameraId} .image-card`).attr('src', networkData[receivedAddress].cameraImagePaths[cameraId]);
            console.log(`Image path for camera ${cameraId} (network ${receivedAddress}): ${networkData[receivedAddress].cameraImagePaths[cameraId]}`);
        }
    });
}

function handleHeartbeatMessage(data) {
    // TODO: 接收心跳时更新ONLINE-OFFLINE状态
    let spanElement = document.getElementById(`d-${data.network_add}.${data.node_add}`);
    console.log("Found heartbeat element:", spanElement);
}

function clearTableForCamera(networkAddress, cameraId) {
    // 仅清除当前网络下该摄像头的表格数据
    $(`#tableZone${networkAddress}_${cameraId} [data-zone] td:not(:first-child)`).text('-');
}

关键修复点说明

  • DOM元素隔离:给每个网络的摄像头元素添加网络地址前缀,彻底解决不同网络间的ID冲突,确保各网络数据独立存储和显示。
  • 移除不合理更新限制:删除仅当单元格为'-'才更新的逻辑,保证每次收到数据都能正确刷新对应网络的摄像头数据。
  • 简化清除逻辑:去掉冗余的currentNetworkAddress判断,直接根据当前接收的网络地址清除对应数据,避免逻辑混乱。

内容的提问来源于stack exchange,提问作者Surya Chandra Mohan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 11:58:13