fix(iot): 修复JT808事件消息identifier字段不匹配问题

- 修复 parseButtonEventAsEvent 使用 eventId 而非 identifier
- 添加消息体长度校验,防止越界访问
- 解码失败时返回 null 而非抛异常,避免断开连接

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-01-21 18:04:21 +08:00
parent 447ea8fe90
commit eb5513f9b6
2 changed files with 37 additions and 4 deletions

View File

@@ -90,11 +90,20 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
// 2. 解析为 JT808 数据包
Jt808DataPack dataPack = decoder.bytes2PackageData(unescapedBytes);
// 3. 转换为统一的 IotDeviceMessage
// 3. 检查消息体是否有效null 表示长度不匹配错误,空数组表示合法的空消息体如心跳)
if (dataPack.getBodyBytes() == null) {
// 长度不匹配,返回 null 由上层跳过该消息
log.warn("[decode][消息体长度不匹配跳过该消息消息ID=0x{}]",
Integer.toHexString(dataPack.getPackHead().getId()));
return null;
}
// 4. 转换为统一的 IotDeviceMessage包括空消息体的消息如心跳
return convertToIotDeviceMessage(dataPack);
} catch (Exception e) {
log.error("[decode][JT808 消息解码失败,数据长度: {}]", bytes.length, e);
throw new RuntimeException("JT808 消息解码失败: " + e.getMessage(), e);
// 解码失败返回 null不断开连接
return null;
}
}
@@ -208,7 +217,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
*
* 物模型标准格式:
* {
* "eventId": "button_event",
* "identifier": "button_event",
* "eventTime": 1234567890,
* "params": {
* "keyId": 1,
@@ -225,7 +234,8 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
Map<String, Object> result = new HashMap<>();
// 统一使用一个事件标识符,通过 isLongPress 参数区分短按和长按
result.put("eventId", "button_event");
// 注意:必须使用 "identifier" 字段,以便 IotDeviceMessageUtils.getIdentifier() 正确提取
result.put("identifier", "button_event");
// 事件时间戳
result.put("eventTime", System.currentTimeMillis());

View File

@@ -43,6 +43,29 @@ public class Jt808Decoder {
msgBodyByteStartIndex = 16;
}
// 验证消息体长度,防止越界
int expectedBodyLength = msgHeader.getBodyLength();
int actualAvailableLength = data.length - msgBodyByteStartIndex - 1; // -1 for checksum
// 检查数据长度是否足够(至少要包含消息头和校验码)
if (data.length < msgBodyByteStartIndex + 1) {
log.warn("[bytes2PackageData][数据长度不足: 头部需要={}, 实际={}, 消息ID=0x{}]",
msgBodyByteStartIndex + 1, data.length, Integer.toHexString(msgHeader.getId()));
ret.setBodyBytes(null); // 使用 null 标记错误状态
ret.setCheckSum(0);
return ret;
}
if (expectedBodyLength > actualAvailableLength) {
log.warn("[bytes2PackageData][消息体长度不匹配: 头部声明={}, 实际可用={}, 数据总长度={}, 消息ID=0x{}]",
expectedBodyLength, actualAvailableLength, data.length,
Integer.toHexString(msgHeader.getId()));
// 使用 null 标记长度不匹配(区别于合法的空消息体如心跳)
ret.setBodyBytes(null);
ret.setCheckSum(data[data.length - 1]);
return ret;
}
byte[] bodyBytes = new byte[msgHeader.getBodyLength()];
System.arraycopy(data, msgBodyByteStartIndex, bodyBytes, 0, bodyBytes.length);
ret.setBodyBytes(bodyBytes);