记坑:JavaScript 的 console.log() 和 trim() 方法IE兼容性

本文探讨了IE9及以下浏览器中console.log()和原生JavaScript trim()方法的兼容性问题,提供了替代解决方案,包括使用jQuery的trim()方法和自定义trim()方法,确保跨浏览器兼容性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、IE9及以下浏览器不支持 console.log()

IE9及以下浏览器不支持 console.log(),所以如果js代码中含有console.log,会导致执行js到这里的时候就直接抛出异常,
后续的js代码也不会被执行了(报错:无console对象),这样就会引出页面的bug。
当这些老版本的IE打开F12 调试窗口时,console.log才能解析了,也不会引出页面bug。

解决办法:
1、最好的办法就是避免使用console.log,即使是开发调试阶段,
如果调试需要引入,而程序又得兼容IE9或更老版本的,注意程序在发布之前一定要记得删掉所有的console.log。

2、define it!

  if (typeof console == "undefined") {
      this.console = {log: function() {}};
  }

参考教程–StackOverflow论坛关于console.log兼容性的问答:
https://stackoverflow.com/questions/14695422/ie10-console-log-not-working

###/2、原生javascrpit的trim() 在老版IE中不被支持
错误示范:

var ID = document.getElementByID('rep_id').value.trim();

IE8 肯定是不支持原生javascrpit的trim()方法的,IE9 待确定(但估计也是不兼容的)。所以如果使用了就会报错。

解决办法:
1、不要使用原生js的trim()方法,如果引入了jquery,那么就使用jquery的 $.trim(…)方法,这个是兼容的。
2、或者就参考jquery那样,自定义实现一个trim()方法原型,然后再程序中使用这个自定义的trim()方法:
实现代码:

String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g,"");
}

或者

if(typeof String.prototype.trim !== 'function') {
  String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, ''); 
  }
}

参考教程–StackOverflow论坛关于 JavaScript trim() 兼容性的问答:
https://stackoverflow.com/questions/2308134/trim-in-javascript-not-working-in-ie?r=SearchResults

// 按照实际铁路线路组织数据 organizeRailwayData() { this.railwayData.stations = []; this.railwayData.routes = []; this.mapList.forEach(station => { const stationObj = { id: station.stationName, name: station.stationName, longitude: station.stationLongitude, latitude: station.stationLatitude, last: station.stationLast, next: station.stationNext, belong: station.stationBelong, line: station.stationLine, importance: station.stationMarkpriority || 3 }; this.railwayData.stations.push(stationObj); // 处理线路,可能一个站点在多个线路上 const lines = station.stationLine.split(','); // 使用英文逗号分割线路名称 lines.forEach(line => { // 去除可能的前后空格 const trimmedLine = line.trim(); // 如果该线路名称不在routes中,添加该线路 if (!this.railwayData.routes.includes(trimmedLine)) { //console.log(`新建:${trimmedLine}`); this.railwayData.routes.push(trimmedLine); } }); }); console.log(处理完成:${this.railwayData.stations.length}个站点); console.log(处理完成:${this.railwayData.routes.length}条线路); }, 我给你的第一个数据是一个控制台打印出来的数据,但是我通过这个方法写出来的路线不全,请你帮我分析主要的原因,同时逗号的去除也已经存在 有些站点的上下站都只有一个会不会可能出现渲染不全的问题呢,如果有请解决,并且保证如果这里出现的方法但是没有发生变化的时候尽可能不修改,且最后传递到渲染数据的时候数据结构尽可能不发生改变
03-28
const axios = require('axios'); const fs = require('fs'); const path = require('path'); const logDirectory = path.join(__dirname, 'log'); const express = require('express'); const app = express(); const cors = require('cors'); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cors()); const mqtt = require('mqtt'); const WebSocket = require('ws'); const ws = require('ws'); const schedule = require('node-schedule'); //测试服 const wsUrl = 'ws://192.168.1.252:8852/eam/websocket/lora'; // const wsUrl = 'ws://192.168.1.195:8081/eam/websocket/lora'; let wsClient = new ws(wsUrl); if(!fs.existsSync(logDirectory)) { fs.mkdirSync(logDirectory); } function getLogFileName(){ const date = new Date(); const year =date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return path.join(logDirectory, `${year}-${month}-${day}.txt`); } function cleanOldLogs(){ const files = fs.readdirSync(logDirectory); const now = new Date(); files.forEach(file => { const filePath = path.join(logDirectory, file); const fileStats = fs.statSync(filePath); const fileDate = new Date(fileStats.mtime); const diffTime = Math.abs(now - fileDate); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays > 15){ fs.unlinkSync(filePath); } }); } function logMessage(message) { const logFileName = getLogFileName(); const logStream = fs.createWriteStream(logFileName, { flags: 'a' }); logStream.write(message); logStream.end(); } const originalLog = console.log; const originalError = console.error; console.log = (...args) => { const message = `${new Date().toISOString()} - LOG:${args.join(' ')}\n`; logMessage(message); originalLog.apply(console, args); }; console.error = (...args) => { const message = `${new Date().toISOString()} - ERROR:${args.join(' ')}\n`; logMessage(message); originalError.apply(console, args); }; //以上为日志相关以及依赖库引用 setInterval(cleanOldLogs, 24 * 60 * 60 * 1000); //redis const redis = require('redis'); const { status } = require('express/lib/response'); const { off } = require('process'); const client = redis.createClient({ // url: 'redis://192.168.1.252:6379' url: 'redis://127.0.0.1:6379' }); client.on('error', (err) => { console.error('Redis Client Error', err); }); client.connect().then(() => { console.log('Connected to Redis'); client.select(0) .then(() => { console.log('已切换到数据库', 0); }) .catch(error => { console.error('数据库切换失败', error); }); }).catch((err) => { console.error('Failed to connect to Redis', err); }); const Redis_KEY_PATTERNS = { MODEL_DEVEUI: (custid, specid) => `LORA:MODEL:POWER:${custid}:${specid}`, MODEL_VAL: (custid, specid) => `LORA:MODEL:POWER:${custid}:${specid}:VAL` }; const modelDataStore = { deviceMap: new Map(), //key: devEUI value: {custid,specid} specDeviceMap: new Map(), //key: {custid}-{specid} value: Set<devEUI> thresholdMap: new Map(), //key: {custid}-${specid} value:{work,await} } wsClient.on('open', () => { console.log('WebSocket连接成功'); }); //监听消息事件,增加查询保存设备列表以及对应规格信号数据 wsClient.on('message', (message) => { const msg = message.toString(); if (msg.startsWith('modelPower-') || msg.startsWith('modelDevices-')){ console.log('系统更新内容:',msg); const [type, key] = msg.split('-'); const parts = key.split(':'); const custid = parts[3]; const specid = parts[4]; if (type === 'modelDevices'){ refreshModelDevices(custid, specid); } else if (type === 'modelPower'){ refreshModelThresholds(custid, specid); } return; } else if (msg !== 'lora_refresh' && msg !== '连接成功!'){ resetHours(message); } else { // console.log('收到消息:',msg); } }); // WebSocket 客户端连接断开后的回调 wsClient.on('close', () => { console.error('WebSocket连接已关闭'); reconnect(); }); // WebSocket 客户端连接错误后的回调 wsClient.on('error', (error) => { console.error('WebSocket 错误: ', error); wsClient.close(); }); const messageQueue = []; //Websocket 重连 function reconnect() { console.log('正在重连……'); if(wsClient){ wsClient.close(); }; setTimeout(() => { wsClient = new WebSocket(wsUrl); wsClient.on('open', () => { console.log('WebSocket连接成功'); while (messageQueue.length > 0) { const message = messageQueue.shift(); wsClient.send(message); } }); wsClient.on('close', () => { console.error('WebSocket连接已关闭'); reconnect(); }); wsClient.on('error', (error) => { console.error('WebSocket 错误: ', error); wsClient.close(); }); wsClient.on('message', (message) => { const msg = message.toString(); if (msg.startsWith('modelPower-') || msg.startsWith('modelDevices-')){ const [type, key] = msg.split('-'); const parts = key.split(':'); const custid = parts[3]; const specid = parts[4]; if (type === 'modelDevices'){ refreshModelDevices(custid, specid); } else if (type === 'modelPower'){ refreshModelThresholds(custid, specid); } return; } else if (msg !== 'lora_refresh' && msg !== '连接成功!'){ resetHours(message); } else { console.log('收到消息:',msg); } }); }, 10000); }; const epcCache = new Map(); function getCurrentTime() { const now = new Date(); const year = now.getFullYear(); const month = (now.getMonth() + 1).toString().padStart(2, '0'); const day = now.getDate().toString().padStart(2, '0'); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); const seconds = now.getSeconds().toString().padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; }; const options = { host: '123.207.3.132', port: 1883, username: 'admin', password: 'admin', }; const mqttClient = mqtt.connect(options); mqttClient.on('connect', () => { console.log('MQTT客户端已连接'); // 订阅主题 const topic = 'application/+/device/+/event/up'; mqttClient.subscribe(topic, { qos: 1 }, (err) => { if (err) { console.error('订阅失败:', err); } else { console.log(`已订阅主题: ${topic}`); } }); }); const knownDevEUIs = new Set(); const lastData = {}; let workHoursStorage = {}; let workCustid = {}; let workError = new Set(); let awaitHoursStorage = {}; let readDevices = [ { devEUI: '0080e10101010123', applicationID: '1', custid: 'GZYS' } ]; // 当客户端接收到消息时 mqttClient.on('message',handleMQTTMessage); async function handleMQTTMessage(topic, message) { const mqttMessage = JSON.parse(message); const mqttDataBase64 = mqttMessage.data; const mqttDataBytes = Buffer.from(mqttDataBase64, 'base64'); // 提取所需的字段 const { deviceName, applicationID, applicationName, devEUI, fPort } = mqttMessage; const gatewayName = mqttMessage.rxInfo[0].name; const gatewayID = mqttMessage.rxInfo[0].gatewayID; // 判断是否包含特定前缀 const containsPrefix = mqttDataBytes.toString('hex').startsWith('5a0001'); const rightData = mqttDataBytes.toString('hex').startsWith('53472000') && mqttDataBytes.toString('hex').length === 64; if (containsPrefix) { const mqttDataHex = mqttDataBytes.toString('hex'); // const epcStartIndex = 20;//从第二十位开始提取epc编号 ps:出现过一次epc编号并非在第二十位开始的情况,暂不清楚原因 const epcStartIndex = mqttDataHex.indexOf('e');//从第一个e开始提取epc编号 const epcLength = 24; const epc = (mqttDataHex.substring(epcStartIndex, epcStartIndex + epcLength)).toUpperCase();//已将字母转为大写 const mqttDataUtf8 = mqttDataBytes.toString('utf-8'); // 提取 readerSerialNumber const numberIndex = mqttDataUtf8.indexOf('N'); const numberLength = 20; const readerSerialNumber = (mqttDataUtf8.substring(numberIndex, numberIndex + numberLength).toUpperCase()).toString('UTF-8'); const epcCacheEntry = epcCache.get(epc); const currentTime = getCurrentTime(); if (epcCacheEntry && (new Date(currentTime) - new Date(epcCacheEntry.timestamp)) < 5000) { return; } // 准备要发送的数据 const backendData = { "cid": "lora", "message": "lora_rfid_inout", "custid": "GZYS", "time": getCurrentTime(), "devEUI": devEUI, "deviceName": deviceName, "readerSerialNumber": readerSerialNumber, "epc": epc }; // 将数据转换为 JSON 字符串 const mqttString = JSON.stringify(backendData); // 更新缓存中的 epc 编号时间戳 epcCache.set(epc, { timestamp: currentTime }); } else if(rightData) { let mqttData = mqttDataBytes.toString('hex'); const openStart = 8; const openEnd = 10; const electricityStart = 12; const electricityEnd = 20; const powerStart = 20; const powerEnd = 28; const currentStart = 28; const currentEnd = 32; const voltageStart = 32; const voltageEnd = 36; const lightStart = 44; const lightEnd = 48; const USBStart = 48; const USBEnd = 56; const openHex = mqttData.substring(openStart, openEnd); const electricityHex = mqttData.substring(electricityStart, electricityEnd); const powerHex = mqttData.substring(powerStart, powerEnd); const currentHex = mqttData.substring(currentStart, currentEnd); const voltageHex = mqttData.substring(voltageStart, voltageEnd); const lightHex = mqttData.substring(lightStart,lightEnd); const USB = mqttData.substring(USBStart,USBEnd); const electricity = parseInt(electricityHex, 16) * 0.001; const power = parseInt(powerHex, 16) * 0.1; const current = parseInt(currentHex, 16) * 0.001; const voltage = parseInt(voltageHex, 16) * 0.01; const light = (parseInt(lightHex.substring(1,2), 16)).toString(2).padStart(4, '0'); const isReadDevices = readDevices.find(device => device.devEUI === devEUI && device.applicationID === applicationID ) if (isReadDevices){ const backendData = { "cid": "lora", "message": "lora_reader", "time": getCurrentTime(), "custid": isReadDevices.custid, "devEUI": devEUI, "USB ID": USB } const wsMessage = JSON.stringify(backendData); if (wsClient.readyState === WebSocket.OPEN){ console.log('读卡器:',wsMessage); } else { console.error(`心跳连接断开,读写器${devEUI}消息传递失败`); } return; } else { const deviceInfo = modelDataStore.deviceMap.get(devEUI); if (!deviceInfo){ console.error(`${devEUI}未配置规格型号`); return; } const thresholds = modelDataStore.thresholdMap.get(`${deviceInfo.custid}-${deviceInfo.specid}`); const backendData = { "cid": "lora", "message": "lora", "custid": deviceInfo.custid, "time": getCurrentTime(), "applicationID": applicationID, "applicationName": applicationName, "gatewayName": gatewayName, "gatewayID": gatewayID, "devEUI": devEUI, "deviceName": deviceName, "fPort": fPort, "data": mqttData }; console.log(`消息来自application/${applicationID}/devEUI/${devEUI},内容为${mqttData}`); // console.log(`电量: ${electricity} 度,获取数据为${electricityHex}`); // console.log(`功率: ${power} W,获取数据为${powerHex}`); // console.log(`电流: ${current} A,获取数据为${currentHex}`); // console.log(`电压: ${voltage} V,获取数据为${voltageHex}`); console.log(`警告灯: ${light},获取数据为${lightHex}`); console.log(`位置ID为${USB}`); console.log(`插座状态${openHex}`); await updateGatewayStatus(gatewayID, gatewayName); // 将数据转换为 JSON 字符串 let mqttString = JSON.stringify(backendData); const value = power > thresholds.work ? '\"work\"' : power > thresholds.await ? '\"await\"' : '\"on\"'; deviceStatus(backendData.custid,backendData.devEUI,value); if (USB !== '00000000' && USB != null) { if (value === '\"work\"') { const custid = backendData.custid; const devEUI_USB = `${backendData.devEUI}_${USB}`; if (!workHoursStorage[custid]){ workHoursStorage[custid] = {}; } if (workHoursStorage[custid][devEUI_USB]){ workHoursStorage[custid][devEUI_USB] += 10; } else { workHoursStorage[custid][devEUI_USB] = 10; } }else if (value === '\"await\"') { const custid = backendData.custid; const devEUI_USB = `${backendData.devEUI}_${USB}`; if (!awaitHoursStorage[custid]){ awaitHoursStorage[custid] = {}; } if (awaitHoursStorage[custid][devEUI_USB]){ awaitHoursStorage[custid][devEUI_USB] += 10; } else { awaitHoursStorage[custid][devEUI_USB] = 10; } } if (openHex === '00') { let params = { "deviceQueueItem": { "confirmed": true, "data": "U0cFAQE=", "devEUI": devEUI, "fPort": 2, "jsonObject": "" } } console.log(`${devEUI}加密狗已上线,允许插座通电`); sendRequests(params); } } else if ((USB === '00000000' || USB == null) && openHex === '01'){ let params = { "deviceQueueItem": { "confirmed": true, "data": "U0cFAQA=", "devEUI": devEUI, "fPort": 2, "jsonObject": "" } } console.log(`${devEUI}加密狗已离线,不允许插座通电`); sendRequests(params); } //转义字符串 function escapeString(str) { return str.replace(/\\/g, '\\\\') .replace(/"/g, '\\"'); } const dataString = "\"" + escapeString(mqttString) + "\""; const lightData = "\"" + escapeString(light) + "\""; if (!knownDevEUIs.has(`${USB}-${backendData.devEUI}`)) { knownDevEUIs.add(`${USB}-${backendData.devEUI}`); } const last = lastData[devEUI] || {}; const dataChanged = !last || last.USB !== USB; if(dataChanged || (last.light !== '0000' && light === '0000')) { lastData[devEUI] = { light: light, USB: USB, time: getCurrentTime(), custid: backendData.custid }; if(wsClient.readyState === WebSocket.OPEN) { if (!last.light || (last.light !== '0000' && light === '0000')) { client.set(`EAM:LORA:BILL:LIGHT:TYPE:${backendData.custid}_${backendData.devEUI}`,lightData); } wsClient.send(mqttString); console.log("位置改变",backendData.time); }else{ messageQueue.push(mqttString); } }else{ lastData[devEUI] = { light: light, USB: USB, time: getCurrentTime(), custid: backendData.custid }; if(light !== '0000' && wsClient.readyState === WebSocket.OPEN) { client.set(`EAM:LORA:BILL:LIGHT:TYPE:${backendData.custid}_${backendData.devEUI}`,lightData); wsClient.send(mqttString); console.log("灯光改变"); }; }; const expireTime = Date.now() + 3900000; client.ZADD(`LORA:GATEWAY:${USB}:${backendData.devEUI}`, {"score":expireTime,"value": dataString}) .catch(error => { console.error('error', error); }); } } else { let mqttData = mqttDataBytes.toString('hex'); const backendData = { 'cid': 'lora', 'message': 'lora', 'custid': 'GZYS', 'time': getCurrentTime(), 'applicationID': applicationID, 'applicationName': applicationName, 'gatewayName': gatewayName, 'gatewayID': gatewayID, 'devEUI': devEUI, 'deviceName': deviceName, 'fPort': fPort, 'data': mqttData }; console.error(`错误格式的数据来自application/${applicationID}/devEUI/${devEUI},内容为${mqttData}`); let mqttString = JSON.stringify(backendData); function escapeString(str) { return str.replace(/\\/g, '\\\\') .replace(/"/g, '\\"'); } const dataString = "\"" + escapeString(mqttString) + "\""; if (!workError.has(`${backendData.custid}-${backendData.devEUI}`)) { workError.add(`${backendData.custid}-${backendData.devEUI}`); wsClient.send(); } // const expireTime = Date.now() + 1296000000; //半个月 const expireTime = Date.now() + 24 * 60 * 60 * 1000; //一天 client.ZADD(`LORA:GATEWAY:${backendData.custid}:ERROR:${backendData.devEUI}`,{"score":expireTime,'value': dataString}) .catch(err => { console.error('保存错误日志时出现错误',err); }) } } function escapeString(str) { // return str.replace(/_/g, '\\_'); return str .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') .replace(/:/g, '\\:') .replace(/;/g, '\\;'); } async function sendRequests(params) { for (let i = 0; i < 3; i++){ try { if (params.deviceQueueItem.devEUI === '0080e10101010110') { const res = await axios.post( `http://123.207.3.132:8080/api/devices/${params.deviceQueueItem.devEUI}/queue`, params, { headers: { Authorization: `Bearer ${jwt}`, } } ); console.log(`第${i+1}次触发成功`,res.status); } } catch (err){ console.error(`第${i+1}次触发失败`,err.response.data || err); } await new Promise(resolve => setTimeout(resolve, 1000)); } } setInterval(() => { Object.keys(workHoursStorage).forEach(custid => { const entries = workHoursStorage[custid]; const entriesArray = Object.keys(entries).map(devEUI_USB => { return `${devEUI_USB}:${entries[devEUI_USB]}`; }) const valueString = JSON.stringify(entriesArray.join(';')); // const value = "\"" + escapeString(valueString) + "\""; client.set(`LORA:GATEWAY:${custid}:WORKHOURS`, valueString) .catch(err => { console.error('工作时长存储错误',err); }); }); Object.keys(awaitHoursStorage).forEach(custid => { const entries = awaitHoursStorage[custid]; const entriesArray = Object.keys(entries).map(devEUI_USB => { return `${devEUI_USB}:${entries[devEUI_USB]}`; }) const valueString = JSON.stringify(entriesArray.join(';')); client.set(`LORA:GATEWAY:${custid}:AWAITHOURS`, valueString) .catch(err => { console.error('待机时长存储错误',err); }) }) }, 30000); const get = { 'cid': 'lora', 'message': 'lora_position_get_custid' }; const getString = JSON.stringify(get); const rule = new schedule.RecurrenceRule(); rule.hour = 23; rule.minute = 59; const job = schedule.scheduleJob(rule, async () => { try { wsClient.send(getString); await resetError(); await refreshAllThresholds(); } catch (err) { console.error('定时任务失败:',err); } }) async function resetError() { try { console.log('开始清理错误数据'); const errorKeys = await client.KEYS('LORA:GATEWAY:*:ERROR:*'); await Promise.all(errorKeys.map(async (key) => { try { const members = await client.zRange(key, 0, -1); const memberScores = await Promise.all(members.map(async (member) => ({ member, score: await client.zScore(key, member) }))); const toRemove = memberScores.filter(({ score }) => { const isValid = !isNaN(score) && score <= Date.now(); return isValid; }).map(({ member }) => member); if (toRemove.length > 0){ await client.zRem(key, toRemove); }else{ console.log(`${key}无过期数据`); } } catch (err) { console.error(`处理${key}失败:`,err); } })) } catch (err) { console.error('错误处理失败:',err); } } async function resetHours(message){ workHoursStorage = {}; awaitHoursStorage = {}; workCustid = message.toString().split(',').filter(element => element !== ''); console.log('已经调用resetHorus函数,获取到workCustid:',workCustid); await Promise.all( workCustid.map(custid => { const key1 = `LORA:GATEWAY:${custid}:WORKHOURS`; return client.get(key1) .then(reply => { return client.set(key1, ' ') .then(reply => { console.log('工作时长已重置',reply); }) }) .catch(err => { console.error('key1处理失败:', custid, err); }); }) ); await Promise.all(workCustid.map(custid => { const key2 = `LORA:GATEWAY:${custid}:AWAITHOURS`; return client.get(key2) .then(reply => { return client.set(key2, ' ') .then(reply => { console.log('待机时长已重置',reply); }) }) .catch(err => { console.error('key2处理失败:', custid, err); }); })) }; function deviceStatus(custid,devEUI,value){ if(value === '\"off\"'){ client.del(`EAM:LORA:BILL:LIGHT:TYPE:${custid}_${devEUI}`); client.setEx(`EAM:LORA:BILL:TYPE:${custid}_${devEUI}`,1800,value); }else{ client.setEx(`EAM:LORA:BILL:TYPE:${custid}_${devEUI}`,60,value); } } function checkAndClearOldData() { const currentTime = Date.now(); for (const devEUI in lastData) { if (currentTime - new Date(lastData[devEUI].time).getTime() > 60000) { deviceStatus(lastData[devEUI].custid,devEUI,'\"off\"'); const lightData = "\"" + '0000' + "\""; client.set(`EAM:LORA:BILL:LIGHT:TYPE:${lastData[devEUI].custid}_${devEUI}`, lightData); delete lastData[devEUI]; console.log(`设备 ${devEUI} 的状态已被删除,因为超过一分钟没有接收到数据。`); } }; //定期清理epcCache中的内容 // epcCache.forEach((value, key) => { // if (currentTime - value.timestamp > 5000) epcCache.delete(key); // }); } // 设置定时器,每分钟调用一次checkAndClearOldData函数 setInterval(checkAndClearOldData, 60000); async function refreshModelDevices(custid, specid) { try { const devices = await client.get(Redis_KEY_PATTERNS.MODEL_DEVEUI(custid, specid)); const validDevices = (devices || '').split(',').map(d => d.replace(/["']/g, '').trim()).filter(d => d !== ''); updateModelDevices(custid, specid, validDevices); console.log(`[设备更新] ${custid}-${specid} 完成,设备数量: ${validDevices.length}`); } catch (err) { console.error(`[设备更新] ${custid}-${specid} 失败:`, err.message); } } async function refreshModelThresholds(custid, specid) { try { const thresholdsVal = await client.get(Redis_KEY_PATTERNS.MODEL_VAL(custid, specid)); if (thresholdsVal){ const cleanedVal = thresholdsVal.replace(/["']/g, '').trim(); const parts = cleanedVal.split(',').map(s => s.trim()).filter(s => s !== ''); if (parts.length !== 3){ throw new Error(`非法阈值格式:${thresholdsVal}`); } const parsed = parts.map((s, idx) => { const num = parseFloat(s); return num; }); [, standby, work] = parsed; } updateModelThresholds(custid, specid, { standby, work }); console.log(`[阈值更新] ${custid}-${specid} 完成,新阈值: standby=${standby}, work=${work}`); } catch (err) { console.error(`[阈值更新] ${custid}-${specid} 失败:`, err.message); } } function updateModelDevices(custid, specid, newDevices) { const specKey = `${custid}-${specid}`; const oldDevices = modelDataStore.specDeviceMap.get(specKey) || new Set(); oldDevices.forEach(devEUI => { if (!newDevices.includes(devEUI)){ modelDataStore.deviceMap.delete(devEUI); } }); newDevices.forEach(devEUI => { if(!modelDataStore.deviceMap.has(devEUI)){ modelDataStore.deviceMap.set(devEUI, { custid, specid }); } }); modelDataStore.specDeviceMap.set(specKey, new Set(newDevices)); } function updateModelThresholds(custid, specid, thresholds) { const specKey = `${custid}-${specid}`; modelDataStore.thresholdMap.set(specKey, { await: thresholds.standby, work: thresholds.work }); } async function refreshAllThresholds() { try { const deviceKeys = await client.KEYS(Redis_KEY_PATTERNS.MODEL_DEVEUI('*','*')); const thresholdKyes = await client.KEYS(Redis_KEY_PATTERNS.MODEL_VAL('*','*')); await Promise.all(deviceKeys.map(key => { const [,,, custid, specid] = key.split(':'); return refreshModelDevices(custid, specid); })); await Promise.all(thresholdKyes.map(key => { const [,,, custid, specid] = key.split(':'); return refreshModelThresholds(custid, specid); })); // console.log('全量:',modelDataStore); } catch (err) { console.error('全量阈值同步失败:',err); } } refreshAllThresholds(); //设备上传数据设置到期删除 setInterval(() => { const currentTime = Date.now(); knownDevEUIs.forEach((key) => { const [USB, devEUI] = key.split('-'); const zSetName = `LORA:GATEWAY:${USB}:${devEUI}`; client.zRange(zSetName, "0", "-1","WITHSCORES") .then(members => { Promise.all(members.map(member => client.zScore(zSetName, member))) .then(scores => { scores.forEach((score, index) => { if (score <= currentTime) { client.zRem(zSetName, members[index]) .catch(err => { console.error('移除成员失败:', err); }); } }); }) .catch(err => { console.error('获取分数失败:', err); }); }) .catch(err => { console.error('获取数据失败:', err); }); }); }, 300000); // 当客户端断开连接时 mqttClient.on('close', () => { console.error('MQTT客户端已断开连接'); mqttReconnect(); }); function mqttReconnect() { console.log('MQTT重连中'); if (mqttClient){ mqttClient.end(true); }; setTimeout(() => { mqttClient = mqtt.connect(options); mqttClient.on('connect', () => { const topic = 'application/+/device/+/event/up'; mqttClient.subscribe(topic, { qos: 1 }, (err) => { if (err) { console.error('订阅失败:',err); } else { console.log('已订阅主题:',topic); } }) }); mqttClient.on('message', handleMQTTMessage); mqttClient.on('close', () => { console.error('MQTT客户端已断开连接'); mqttReconnect(); }); mqttClient.on('error', (err) => { console.error('MQTT客户端发生错误:', err); mqttClient.end(true); }); }, 5000); } // 当客户端发生错误时 mqttClient.on('error', (err) => { console.error('MQTT客户端发生错误:', err); mqttClient.end(true); }); let jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGlfa2V5X2lkIjoiZjA5ZjViMWYtYTFjMy00NjZkLTkyNjItOGE1YTkzYTY1NTU5IiwiYXVkIjoiYXMiLCJpc3MiOiJhcyIsIm5iZiI6MTczMjU5MTM5Niwic3ViIjoiYXBpX2tleSJ9.32w2IsaBTTM8nZuKHxwwXJwT-mAeR2B5ubkDzMgU1XA'; let offGateways = []; //从redis中获取离线网关的名单 function loadGateways(){ client.keys(`LORA:GATEWAYSTATUS:*:*`).then(reply => { offGateways = []; reply.forEach(key => { const parts = key.split(':'); const organizationName = parts[2]; const gatewayID = parts[3]; offGateways.push({ organizationName, gatewayID }); }); }).catch(err => { console.error("获取离线网关名单时出错",err); }); } //获取绑定组织名称ID function getOrgID(){ axios.get(`http://123.207.3.132:8080/api/organizations?limit=99999`, { headers: { Authorization: jwt, } }).then(response => { const orgMap = new Map(); response.data.result.forEach(org => { orgMap.set(org.id, org.name); }); checkGatewayStatus([...orgMap.keys()], orgMap); }) .catch(err => { console.error("获取ID出现错误",err) }) }; //网关工作情况 function checkGatewayStatus(organizationIDs,orgIdNameMap) { const promises = organizationIDs.map(async orgID => { try { const response = await axios.get(`http://123.207.3.132:8080/api/gateways?limit=99999&offset=0&organizationID=${orgID}`, { headers: { Authorization: jwt, } }); const rawOrgName = orgIdNameMap.get(orgID); const safeOrgName = rawOrgName.replace(/[^a-zA-Z0-9]/g, '_'); response.data.result.forEach(gateway => { const gatewayID = gateway.id; const redisKey = `LORA:GATEWAYSTATUS:${safeOrgName}:${gatewayID}`; const lastSeenAt = gateway.lastSeenAt ? new Date(gateway.lastSeenAt).getTime() : null; const isOffline = lastSeenAt && (Date.now() - lastSeenAt) > 32000; if (isOffline){ const exists = offGateways.some(gw => gw.gatewayID === gatewayID); if (!exists){ offGateways.push({ organizationName: rawOrgName, gatewayID }); } client.set(redisKey, '\"off\"').then(() => console.log(`[${safeOrgName}] 网关${gatewayID} 离线状态已录`)) .catch(err => console.error(`[${safeOrgName}] Redis写入失败`, err)); } else { const index = offGateways.findIndex(gw => gw.gatewayID === gatewayID); if (index !== -1){ offGateways.splice(index, 1); } client.del(redisKey).then(() => console.log(`[${safeOrgName}] 网关${gatewayID} 在线状态已更新`)) .catch(err => console.error(`[${safeOrgName}] Redis删除失败`, err)); } }); } catch (error) { console.error("checkDevicesStatus函数出错", error); } }); Promise.all(promises).then(() => { console.log("离线网关列表",JSON.stringify(offGateways)); }); }; async function updateGatewayStatus(gatewayID, gatewayName) { const index = offGateways.findIndex(gw => gw.gatewayID === gatewayID); if (index !== -1){ const { organizationName } = offGateways[index]; offGateways.splice(index, 1); const safeOrgName = organizationName.replace(/[^a-zA-Z0-9]/g, '-'); const redisKey = `LORA:GATEWAYSTATUS:${safeOrgName}:${gatewayID}`; try { await client.del(redisKey); console.log(`[实时更新] 网关 ${gatewayName} (${gatewayID}) 重新上线`); } catch (err) { console.error(`[${organizationName}] Redis删除失败`, err); } } } loadGateways(); getOrgID(); setInterval(getOrgID, 15000); app.get('/health', async (req, res) => { const allClients = { redis: { connected: client.isReady, name: 'Redis数据库' }, mqtt: { connected: mqttClient.connected, name: 'MQTT消息队列' }, websocket: { connected: wsClient.readyState === WebSocket.OPEN, name: 'WebSocket连接' }, }; const statusReport = { status: 'healthy', allClients: {}, issues: [], timestamp: Date.now() }; let allHealthy = true; Object.entries(allClients).forEach(([key, client]) => { const isConnected = client.connected; statusReport.allClients[key] = isConnected ? 'connected' : 'disconnected'; if (!isConnected) { statusReport.issues.push({ clients: key, name: client.name, description: `${client.name}连接失败` }); allHealthy = false; } }); statusReport.status = allHealthy ? 'healthy' : 'unhealthy'; res.status(allHealthy ? 200 : 503).json(statusReport); }); app.listen(3000); process.on('unhandledRejection', (reason, promise) => { console.error('未处理的拒绝:', reason); }) process.on('uncaughtException', (err) => { console.error('未捕获的异常:', err); }) process.on('SIGINT', () => { console.log('程序正在关闭...'); mqttClient.end(); client.quit(); wsClient.close(); process.exit(); }); 遍历我的代码,查看哪里会发生修改const变量的情况,并且解释一下MQTT客户端发生错误: Error: read ECONNRESET,这是连接超时导致的错误吗
最新发布
07-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值