Ricon组态系统通信配置指南
WebSocket、MQTT、HTTP通信配置详细说明
版本:v1.0.2 | 更新时间:2026年3月
目录
1. 通信概述
1.1 通信方式对比
Ricon组态系统支持三种实时数据通信方式,可根据不同场景需求选择合适的通信协议:
| 通信方式 | 通信模式 | 适用场景 | 性能特点 | 推荐程度 |
|---|---|---|---|---|
| WebSocket | 实时双向通信 | 高频数据更新、实时监控 | 低延迟、高实时性 | ⭐⭐⭐⭐⭐ |
| MQTT | 发布/订阅模式 | IoT设备监控、分布式系统 | 轻量级、适合大量设备 | ⭐⭐⭐⭐ |
| HTTP | 请求/响应轮询 | 低频数据更新、兼容性要求高 | 兼容性好、实现简单 | ⭐⭐⭐ |
1.2 核心特性
- ✅ 多协议支持 - 同时支持WebSocket、MQTT、HTTP三种通信协议
- ✅ 配置灵活 - 支持全局配置和场景级配置
- ✅ 自动重连 - WebSocket和MQTT支持断线自动重连
- ✅ 数据格式统一 - 不同通信方式使用统一的数据处理机制
- ✅ 实时监控 - 连接状态实时显示,便于故障排查
1.3 配置位置
1.3.1 场景级配置(推荐)
在编辑器中,通过以下路径配置:
- 打开编辑器页面 (
editor.html) - 在右侧属性面板中选择"画布属性"标签
- 找到"通信配置"部分进行详细配置
1.3.2 全局配置
对于WebSocket,还可以在 config/apiClient.js 中进行全局配置:
javascript
var SystemConfig = {
webSocketUrl: "ws://your-server:8080/websocket/message"
};
配置优先级: 场景级配置 > 全局配置
2. WebSocket配置
2.1 配置参数
2.1.1 基础配置
| 配置项 | 说明 | 推荐值 | 注意事项 |
|---|---|---|---|
| WebSocket地址 | WebSocket服务器的完整URL | ws://localhost:8080/ws |
必须以 ws:// 或 wss:// 开头 |
| 心跳间隔 | 客户端发送心跳包的间隔时间(秒) | 10-30秒 | 过短增加服务器负担,过长影响断线检测 |
| 自动重连 | 连接断开后是否自动重连 | 启用 | 建议在稳定网络环境下启用 |
2.1.2 高级配置
| 配置项 | 说明 | 默认值 | 可选值 |
|---|---|---|---|
| 连接超时 | 连接建立超时时间(毫秒) | 10000 | 5000-30000 |
| 重连间隔 | 重连尝试间隔(毫秒) | 3000 | 1000-10000 |
| 最大重连次数 | 最大重连尝试次数 | 5 | 1-10 |
| 消息队列大小 | 离线消息缓存队列大小 | 100 | 50-1000 |
2.2 配置步骤
2.2.1 场景配置
- 在画布属性的通信配置部分,选择通信方式为"WebSocket"
- 填写WebSocket服务器地址(如:
ws://localhost:8080/ws) - 设置心跳间隔(推荐10-30秒)
- 选择是否启用自动重连(推荐启用)
2.2.2 全局配置
编辑 config/apiClient.js 文件:
javascript
var SystemConfig = {
// WebSocket服务地址
webSocketUrl: "ws://your-server:8080/websocket/message",
// WebSocket连接选项
webSocketOptions: {
heartbeat: 10, // 心跳间隔(秒)
reconnect: true, // 自动重连
timeout: 10000, // 连接超时(毫秒)
maxReconnectAttempts: 5 // 最大重连次数
}
};
2.3 连接状态指示
- 🔵 蓝色 - 连接正常
- 🔴 红色 - 连接断开
- 🟡 黄色 - 正在连接/重连中
2.4 数据格式
2.4.1 服务器发送格式
标准格式:
json
{
"MESSAGETYPE": "01",
"MESSAGECONTENT": {
"devicecode1": "value1",
"devicecode2": "value2",
"temperature": 25.5,
"pressure": 1013.25
}
}
消息类型说明:
"01"- 业务数据(更新场景组件数据)"02"- 提醒数据(显示警告信息)"03"- 网络诊断(更新连接状态)"04"- 命令响应(处理命令执行结果)"05"- 心跳消息(维持连接活跃)
2.4.2 客户端发送格式
心跳消息:
json
{
"MESSAGETYPE": "05",
"MESSAGECONTENT": {
"timestamp": "2024-01-01T12:00:00.000Z",
"clientId": "client_001"
}
}
命令消息:
json
{
"MESSAGETYPE": "04",
"MESSAGECONTENT": {
"command": "set_value",
"devicecode": "device001",
"value": 100,
"timestamp": "2024-01-01T12:00:00.000Z"
}
}
2.5 实现代码
2.5.1 WebSocket客户端
javascript
// assets/js/core/webSocketClient.js
class WebSocketClient {
constructor(url, options = {}) {
this.url = url;
this.options = {
heartbeat: options.heartbeat || 10,
reconnect: options.reconnect !== false,
timeout: options.timeout || 10000,
maxReconnectAttempts: options.maxReconnectAttempts || 5,
...options
};
this.ws = null;
this.reconnectAttempts = 0;
this.heartbeatTimer = null;
this.isConnected = false;
}
connect() {
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket connected');
this.isConnected = true;
this.reconnectAttempts = 0;
this.startHeartbeat();
this.onConnect && this.onConnect();
};
this.ws.onmessage = (event) => {
this.handleMessage(event);
};
this.ws.onclose = (event) => {
console.log('WebSocket disconnected:', event.code, event.reason);
this.isConnected = false;
this.stopHeartbeat();
if (this.options.reconnect && this.reconnectAttempts < this.options.maxReconnectAttempts) {
this.reconnect();
}
this.onDisconnect && this.onDisconnect(event);
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
this.onError && this.onError(error);
};
} catch (error) {
console.error('WebSocket connection failed:', error);
this.onError && this.onError(error);
}
}
handleMessage(event) {
try {
const data = JSON.parse(event.data);
switch (data.MESSAGETYPE) {
case "01":
// 业务数据
this.onBusinessData && this.onBusinessData(data.MESSAGECONTENT);
break;
case "02":
// 提醒数据
this.onAlertData && this.onAlertData(data.MESSAGECONTENT);
break;
case "03":
// 网络诊断
this.onNetworkDiagnosis && this.onNetworkDiagnosis(data.MESSAGECONTENT);
break;
case "05":
// 心跳响应
this.onHeartbeatResponse && this.onHeartbeatResponse(data.MESSAGECONTENT);
break;
default:
console.warn('Unknown message type:', data.MESSAGETYPE);
}
} catch (error) {
console.error('Message parse error:', error);
}
}
send(data) {
if (this.isConnected && this.ws) {
this.ws.send(JSON.stringify(data));
} else {
console.warn('WebSocket not connected, message not sent');
}
}
startHeartbeat() {
this.stopHeartbeat();
this.heartbeatTimer = setInterval(() => {
if (this.isConnected) {
this.send({
MESSAGETYPE: "05",
MESSAGECONTENT: {
timestamp: new Date().toISOString(),
clientId: this.clientId
}
});
}
}, this.options.heartbeat * 1000);
}
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
reconnect() {
this.reconnectAttempts++;
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.options.maxReconnectAttempts})`);
setTimeout(() => {
this.connect();
}, delay);
}
disconnect() {
this.options.reconnect = false;
if (this.ws) {
this.ws.close();
}
}
}
2.5.2 使用示例
javascript
// 创建WebSocket客户端
const wsClient = new WebSocketClient('ws://localhost:8080/ws', {
heartbeat: 15,
reconnect: true,
timeout: 10000
});
// 设置事件处理器
wsClient.onConnect = () => {
console.log('Connected to WebSocket server');
// 更新UI连接状态
updateConnectionStatus('connected');
};
wsClient.onDisconnect = (event) => {
console.log('Disconnected from WebSocket server');
// 更新UI连接状态
updateConnectionStatus('disconnected');
};
wsClient.onBusinessData = (data) => {
console.log('Received business data:', data);
// 更新场景数据
stageView.updateStageData(data);
};
wsClient.onError = (error) => {
console.error('WebSocket error:', error);
// 显示错误提示
showError('WebSocket连接错误');
};
// 连接
wsClient.connect();
3. MQTT配置
3.1 前置条件
⚠️ 重要: 使用MQTT功能前必须先引入MQTT.js库。
3.1.1 库引入方式
CDN引入(推荐):
html
<head>
<!-- MQTT.js库 v4.3.7 - 推荐使用固定版本 -->
<script src="https://unpkg.com/mqtt@4.3.7/dist/mqtt.min.js"></script>
<!-- 系统核心文件(MQTT库必须在前面) -->
<script src="assets/js/core/mqttClient.js"></script>
</head>
本地部署:
bash
# 下载MQTT.js库
wget https://unpkg.com/mqtt@4.3.7/dist/mqtt.min.js -O assets/js/libs/mqtt/mqtt.min.js
html
<script src="assets/js/libs/mqtt/mqtt.min.js"></script>
3.2 配置参数
3.2.1 基础配置
| 配置项 | 说明 | 示例值 | 注意事项 |
|---|---|---|---|
| MQTT地址 | MQTT服务器的WebSocket地址 | ws://localhost:9001 |
必须使用WebSocket协议(ws://),不是TCP地址 |
| 客户端ID | 唯一标识符 | mqtt_client_123456 |
必须唯一,建议包含时间戳或随机数 |
| 用户名 | MQTT认证用户名 | admin |
可选,根据服务器配置 |
| 密码 | MQTT认证密码 | password123 |
可选,根据服务器配置 |
| 订阅主题 | 要订阅的消息主题 | /data/device |
支持通配符如 /data/# |
| QoS等级 | 消息质量等级 | 1 | 推荐使用1(至少一次) |
3.2.2 QoS等级详解
| 等级 | 名称 | 说明 | 性能 | 可靠性 | 适用场景 |
|---|---|---|---|---|---|
| 0 | 至多一次 | 消息可能丢失,但不重复 | 最高 | 最低 | 实时性要求高,允许丢数据 |
| 1 | 至少一次 | 消息不丢失,但可能重复 | 中等 | 中等 | 一般监控场景(推荐) |
| 2 | 仅一次 | 消息不丢失不重复 | 最低 | 最高 | 数据准确性要求极高 |
3.3 配置步骤
- 在画布属性的通信配置部分,选择通信方式为"MQTT"
- 填写MQTT服务器WebSocket地址(如:
ws://localhost:9001) - 设置唯一的客户端ID
- 填写用户名和密码(如服务器需要认证)
- 设置要订阅的消息主题
- 选择合适的QoS等级
3.4 数据格式
3.4.1 消息格式
标准JSON格式:
json
{
"devicecode1": "value1",
"devicecode2": "ON",
"temperature": 25.5,
"pressure": 1013.25,
"timestamp": "2024-01-01T12:00:00.000Z"
}
3.4.2 主题设计建议
- 单级主题 -
/data(简单场景) - 多级主题 -
/factory/area1/devices(复杂场景) - 通配符订阅 -
/data/#订阅所有数据主题 - 设备特定主题 -
/device/{deviceId}/data
3.5 实现代码
3.5.1 MQTT客户端
javascript
// assets/js/core/mqttClient.js
class MQTTClient {
constructor(config) {
this.config = {
url: config.url,
clientId: config.clientId || `mqtt_client_${Date.now()}`,
username: config.username,
password: config.password,
topic: config.topic || '/data/device',
qos: config.qos || 1,
reconnectPeriod: config.reconnectPeriod || 1000,
connectTimeout: config.connectTimeout || 30000,
...config
};
this.client = null;
this.isConnected = false;
this.subscribedTopics = new Set();
}
connect() {
const options = {
connectTimeout: this.config.connectTimeout,
clientId: this.config.clientId,
reconnectPeriod: this.config.reconnectPeriod,
clean: true
};
if (this.config.username && this.config.password) {
options.username = this.config.username;
options.password = this.config.password;
}
try {
this.client = mqtt.connect(this.config.url, options);
this.client.on('connect', () => {
console.log('MQTT connected');
this.isConnected = true;
this.onConnect && this.onConnect();
// 订阅主题
this.subscribe(this.config.topic, { qos: this.config.qos });
});
this.client.on('message', (topic, message) => {
try {
const data = JSON.parse(message.toString());
this.onMessage && this.onMessage(topic, data);
} catch (error) {
console.error('MQTT message parse error:', error);
}
});
this.client.on('error', (error) => {
console.error('MQTT error:', error);
this.onError && this.onError(error);
});
this.client.on('close', () => {
console.log('MQTT connection closed');
this.isConnected = false;
this.onDisconnect && this.onDisconnect();
});
this.client.on('reconnect', () => {
console.log('MQTT reconnecting...');
this.onReconnect && this.onReconnect();
});
} catch (error) {
console.error('MQTT connection failed:', error);
this.onError && this.onError(error);
}
}
subscribe(topic, options = {}) {
if (this.isConnected && this.client) {
this.client.subscribe(topic, options, (error, granted) => {
if (error) {
console.error('Subscribe error:', error);
} else {
console.log('Subscribed to:', topic);
this.subscribedTopics.add(topic);
}
});
}
}
unsubscribe(topic) {
if (this.isConnected && this.client) {
this.client.unsubscribe(topic, (error) => {
if (error) {
console.error('Unsubscribe error:', error);
} else {
console.log('Unsubscribed from:', topic);
this.subscribedTopics.delete(topic);
}
});
}
}
publish(topic, message, options = {}) {
if (this.isConnected && this.client) {
const payload = typeof message === 'string' ? message : JSON.stringify(message);
this.client.publish(topic, payload, options, (error) => {
if (error) {
console.error('Publish error:', error);
} else {
console.log('Message published to:', topic);
}
});
} else {
console.warn('MQTT not connected, message not published');
}
}
disconnect() {
if (this.client) {
this.client.end(true, () => {
console.log('MQTT disconnected');
});
}
}
}
3.5.2 使用示例
javascript
// 创建MQTT客户端
const mqttClient = new MQTTClient({
url: 'ws://localhost:9001',
clientId: `mqtt_client_${Date.now()}`,
username: 'admin',
password: 'password123',
topic: '/data/device',
qos: 1
});
// 设置事件处理器
mqttClient.onConnect = () => {
console.log('Connected to MQTT broker');
updateConnectionStatus('connected');
};
mqttClient.onDisconnect = () => {
console.log('Disconnected from MQTT broker');
updateConnectionStatus('disconnected');
};
mqttClient.onMessage = (topic, data) => {
console.log('Received MQTT message:', topic, data);
// 更新场景数据
stageView.updateStageData(data);
};
mqttClient.onError = (error) => {
console.error('MQTT error:', error);
showError('MQTT连接错误');
};
// 连接
mqqttClient.connect();
// 发布消息示例
function sendCommand(deviceId, command, value) {
mqttClient.publish(`/device/${deviceId}/command`, {
command: command,
value: value,
timestamp: new Date().toISOString()
});
}
4. HTTP配置
4.1 配置参数
4.1.1 基础配置
| 配置项 | 说明 | 示例值 | 注意事项 |
|---|---|---|---|
| HTTP地址 | 数据接口的完整URL | http://localhost:8080/api/data |
必须包含协议(http/https) |
| 请求方式 | HTTP请求方法 | GET/POST | 根据API接口要求选择 |
| 轮询间隔 | 请求间隔时间(秒) | 5-60秒 | 过短增加服务器负担 |
| 请求头 | HTTP请求头 | {"Content-Type": "application/json"} |
JSON格式字符串 |
| 请求参数 | 请求参数 | {"deviceId": "device001"} |
JSON格式字符串 |
4.1.2 高级配置
| 配置项 | 说明 | 默认值 | 可选值 |
|---|---|---|---|
| 超时时间 | 请求超时时间(毫秒) | 10000 | 5000-30000 |
| 重试次数 | 请求失败重试次数 | 3 | 1-5 |
| 重试间隔 | 重试间隔(毫秒) | 1000 | 500-5000 |
| 缓存时间 | 响应缓存时间(秒) | 0 | 0-300 |
4.2 配置步骤
- 在画布属性的通信配置部分,选择通信方式为"HTTP"
- 填写HTTP API完整地址(如:
http://localhost:8080/api/data) - 选择HTTP请求方法(GET/POST/PUT/DELETE)
- 设置轮询间隔时间(秒)
- 配置请求头(JSON格式)
- 配置请求参数(JSON格式)
4.3 数据格式
4.3.1 标准响应格式
json
{
"code": 200,
"message": "success",
"data": {
"devicecode1": "value1",
"devicecode2": "value2",
"timestamp": "2024-01-01 12:00:00"
}
}
4.3.2 直接数据格式
接口也可以直接返回数据对象(适用于简单API):
json
{
"devicecode1": "value1",
"devicecode2": "value2",
"temperature": 25.5,
"status": "normal"
}
4.3.3 错误响应格式
json
{
"code": 500,
"message": "Internal server error",
"data": null
}
4.4 多HTTP配置支持
系统支持配置多个HTTP数据源:
- 点击"添加HTTP配置"按钮创建多个配置
- 每个配置独立运行,支持不同的API地址和参数
- 可以单独启用/禁用每个配置
- 所有配置的数据会合并更新到场景
4.5 实现代码
4.5.1 HTTP客户端
javascript
// assets/js/core/httpClient.js
class HTTPClient {
constructor(config) {
this.config = {
url: config.url,
method: config.method || 'GET',
interval: config.interval || 5,
headers: config.headers || {},
params: config.params || {},
body: config.body || {},
timeout: config.timeout || 10000,
retryCount: config.retryCount || 3,
retryInterval: config.retryInterval || 1000,
cacheTime: config.cacheTime || 0,
...config
};
this.isPolling = false;
this.pollingInterval = null;
this.cache = new Map();
this.requestCount = 0;
this.errorCount = 0;
}
async request(options = {}) {
const requestConfig = {
...this.config,
...options
};
const cacheKey = this.getCacheKey(requestConfig);
// 检查缓存
if (this.config.cacheTime > 0) {
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.config.cacheTime * 1000) {
console.log('Using cached response');
return cached.data;
}
}
let lastError = null;
let attempt = 0;
while (attempt <= this.config.retryCount) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
const response = await fetch(requestConfig.url, {
method: requestConfig.method,
headers: this.buildHeaders(requestConfig),
signal: controller.signal,
...this.getRequestOptions(requestConfig)
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
// 缓存响应
if (this.config.cacheTime > 0) {
this.cache.set(cacheKey, {
data: data,
timestamp: Date.now()
});
}
// 重置错误计数
this.errorCount = 0;
return data;
} catch (error) {
lastError = error;
attempt++;
this.errorCount++;
console.error(`HTTP request failed (attempt ${attempt}/${this.config.retryCount}):`, error);
if (attempt <= this.config.retryCount) {
await this.delay(this.config.retryInterval * attempt);
}
}
}
throw lastError;
}
buildHeaders(config) {
const headers = {
'Content-Type': 'application/json',
...config.headers
};
// 添加认证头
if (config.token) {
headers['Authorization'] = `Bearer ${config.token}`;
}
return headers;
}
getRequestOptions(config) {
const options = {};
if (config.method === 'GET') {
// GET请求:参数拼接到URL
if (config.params && Object.keys(config.params).length > 0) {
const url = new URL(config.url);
Object.entries(config.params).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
options.url = url.toString();
}
} else {
// POST/PUT请求:参数放在请求体中
if (config.body && Object.keys(config.body).length > 0) {
options.body = JSON.stringify(config.body);
}
}
return options;
}
getCacheKey(config) {
return `${config.method}:${config.url}:${JSON.stringify(config.params || {})}:${JSON.stringify(config.body || {})}`;
}
startPolling() {
if (this.isPolling) {
console.warn('HTTP polling already started');
return;
}
this.isPolling = true;
console.log('Starting HTTP polling');
const poll = async () => {
if (!this.isPolling) return;
try {
const data = await this.request();
// 处理响应数据
if (data && (data.code === 200 || !data.code)) {
const responseData = data.data || data;
this.onData && this.onData(responseData);
} else {
throw new Error(data.message || 'Invalid response format');
}
} catch (error) {
console.error('HTTP polling error:', error);
this.onError && this.onError(error);
}
// 安排下一次轮询
if (this.isPolling) {
this.pollingInterval = setTimeout(poll, this.config.interval * 1000);
}
};
// 立即执行第一次请求
poll();
}
stopPolling() {
this.isPolling = false;
if (this.pollingInterval) {
clearTimeout(this.pollingInterval);
this.pollingInterval = null;
}
console.log('HTTP polling stopped');
}
async getDataOnce() {
try {
const data = await this.request();
return data.data || data;
} catch (error) {
console.error('HTTP request failed:', error);
throw error;
}
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
getStatus() {
return {
isPolling: this.isPolling,
requestCount: this.requestCount,
errorCount: this.errorCount,
cacheSize: this.cache.size
};
}
clearCache() {
this.cache.clear();
console.log('HTTP cache cleared');
}
}
4.5.2 多HTTP配置管理
javascript
// assets/js/core/httpManager.js
class HTTPManager {
constructor() {
this.clients = new Map();
this.isRunning = false;
}
addClient(id, config) {
if (this.clients.has(id)) {
console.warn(`HTTP client ${id} already exists, replacing...`);
this.removeClient(id);
}
const client = new HTTPClient(config);
// 设置事件处理器
client.onData = (data) => {
this.handleData(id, data);
};
client.onError = (error) => {
this.handleError(id, error);
};
this.clients.set(id, client);
console.log(`HTTP client ${id} added`);
return client;
}
removeClient(id) {
const client = this.clients.get(id);
if (client) {
client.stopPolling();
this.clients.delete(id);
console.log(`HTTP client ${id} removed`);
}
}
startClient(id) {
const client = this.clients.get(id);
if (client) {
client.startPolling();
console.log(`HTTP client ${id} started`);
} else {
console.warn(`HTTP client ${id} not found`);
}
}
stopClient(id) {
const client = this.clients.get(id);
if (client) {
client.stopPolling();
console.log(`HTTP client ${id} stopped`);
}
}
startAll() {
this.isRunning = true;
this.clients.forEach((client, id) => {
client.startPolling();
});
console.log('All HTTP clients started');
}
stopAll() {
this.isRunning = false;
this.clients.forEach((client, id) => {
client.stopPolling();
});
console.log('All HTTP clients stopped');
}
handleData(clientId, data) {
console.log(`Data received from ${clientId}:`, data);
// 合并数据并更新场景
const mergedData = this.mergeData(clientId, data);
this.onData && this.onData(mergedData);
}
handleError(clientId, error) {
console.error(`Error from ${clientId}:`, error);
this.onError && this.onError(clientId, error);
}
mergeData(clientId, newData) {
// 简单的数据合并策略:以后接收的数据为准
// 可以根据需要实现更复杂的合并逻辑
return {
source: clientId,
timestamp: Date.now(),
data: newData
};
}
getClientStatus(id) {
const client = this.clients.get(id);
return client ? client.getStatus() : null;
}
getAllStatus() {
const status = {};
this.clients.forEach((client, id) => {
status[id] = client.getStatus();
});
return status;
}
clearAllCache() {
this.clients.forEach(client => {
client.clearCache();
});
}
}
4.5.3 使用示例
javascript
// 创建HTTP管理器
const httpManager = new HTTPManager();
// 添加多个HTTP数据源
httpManager.addClient('device1', {
url: 'http://api.device1.com/data',
method: 'GET',
interval: 5,
headers: {
'Authorization': 'Bearer token1',
'X-Device-ID': 'device001'
},
params: {
format: 'json'
}
});
httpManager.addClient('device2', {
url: 'http://api.device2.com/sensor',
method: 'POST',
interval: 10,
headers: {
'Authorization': 'Bearer token2'
},
body: {
query: 'latest',
sensors: ['temp', 'humidity', 'pressure']
}
});
// 设置事件处理器
httpManager.onData = (mergedData) => {
console.log('Merged data:', mergedData);
// 更新场景数据
stageView.updateStageData(mergedData.data);
};
httpManager.onError = (clientId, error) => {
console.error(`Error from ${clientId}:`, error);
// 显示错误提示
showError(`${clientId} 数据获取失败: ${error.message}`);
};
// 启动所有客户端
httpManager.startAll();
// 获取状态信息
setInterval(() => {
const status = httpManager.getAllStatus();
console.log('HTTP clients status:', status);
}, 30000);
// 停止特定客户端
function stopDeviceClient(deviceId) {
httpManager.stopClient(deviceId);
}
// 停止所有客户端
function stopAllClients() {
httpManager.stopAll();
}
5. 通信配置管理
5.1 配置存储
5.1.1 配置格式
通信配置作为场景元数据的一部分,随场景数据一起保存:
javascript
// 场景配置中的通信配置
"communicationConfig": {
"websocket": {
"enabled": true,
"url": "ws://localhost:8080/ws",
"heartbeat": 10,
"reconnect": true,
"timeout": 10000
},
"mqtt": {
"enabled": false,
"url": "ws://localhost:9001",
"clientId": "mqtt_client_123456",
"username": "admin",
"password": "password123",
"topic": "/data/device",
"qos": 1
},
"http": [
{
"id": "http1",
"enabled": true,
"url": "http://localhost:8080/api/data1",
"method": "GET",
"interval": 5,
"headers": {
"Content-Type": "application/json"
},
"params": {
"deviceId": "device001"
}
},
{
"id": "http2",
"enabled": false,
"url": "http://localhost:8080/api/data2",
"method": "POST",
"interval": 10,
"headers": {
"Content-Type": "application/json"
},
"body": {
"query": "latest"
}
}
]
}
5.1.2 存储位置
- 存储位置 -
stage.attrs.communicationConfig - 保存时机 - 保存场景时自动包含通信配置
- 数据格式 - JSON格式,包含所有通信方式配置
5.2 配置加载
5.2.1 监控页面初始化流程
加载场景 → 解析通信配置 → 初始化对应客户端 → 建立连接 → 开始数据接收
5.2.2 自动初始化逻辑
javascript
// assets/js/modules/view.js
class ViewCommunicationManager {
constructor(stageView) {
this.stageView = stageView;
this.clients = new Map();
this.communicationConfig = null;
}
initCommunication(config) {
this.communicationConfig = config;
// 停止现有连接
this.stopAll();
// 初始化WebSocket
if (config.websocket && config.websocket.enabled) {
this.initWebSocket(config.websocket);
}
// 初始化MQTT
if (config.mqtt && config.mqtt.enabled) {
this.initMQTT(config.mqtt);
}
// 初始化HTTP
if (config.http && Array.isArray(config.http)) {
this.initHTTP(config.http);
}
}
initWebSocket(config) {
const wsClient = new WebSocketClient(config.url, {
heartbeat: config.heartbeat,
reconnect: config.reconnect,
timeout: config.timeout
});
wsClient.onBusinessData = (data) => {
this.stageView.updateStageData(data);
};
wsClient.onError = (error) => {
console.error('WebSocket error:', error);
};
wsClient.connect();
this.clients.set('websocket', wsClient);
}
initMQTT(config) {
const mqttClient = new MQTTClient({
url: config.url,
clientId: config.clientId,
username: config.username,
password: config.password,
topic: config.topic,
qos: config.qos
});
mqttClient.onMessage = (topic, data) => {
this.stageView.updateStageData(data);
};
mqttClient.onError = (error) => {
console.error('MQTT error:', error);
};
mqttClient.connect();
this.clients.set('mqtt', mqttClient);
}
initHTTP(configs) {
const httpManager = new HTTPManager();
configs.forEach(httpConfig => {
if (httpConfig.enabled) {
httpManager.addClient(httpConfig.id, httpConfig);
}
});
httpManager.onData = (mergedData) => {
this.stageView.updateStageData(mergedData.data);
};
httpManager.onError = (clientId, error) => {
console.error(`HTTP error from ${clientId}:`, error);
};
httpManager.startAll();
this.clients.set('http', httpManager);
}
stopAll() {
this.clients.forEach((client, type) => {
if (type === 'websocket') {
client.disconnect();
} else if (type === 'mqtt') {
client.disconnect();
} else if (type === 'http') {
client.stopAll();
}
});
this.clients.clear();
}
getStatus() {
const status = {};
this.clients.forEach((client, type) => {
if (type === 'websocket') {
status[type] = {
connected: client.isConnected,
url: client.url
};
} else if (type === 'mqtt') {
status[type] = {
connected: client.isConnected,
url: client.config.url,
topic: client.config.topic
};
} else if (type === 'http') {
status[type] = client.getAllStatus();
}
});
return status;
}
}
5.3 配置同步
5.3.1 实时生效
- 实时生效 - 修改场景通信配置后,保存即可生效
- 监控页面 - 重新加载场景或刷新页面应用新配置
- 配置验证 - 保存时会验证配置的有效性
5.3.2 配置验证
javascript
// 通信配置验证
function validateCommunicationConfig(config) {
const errors = [];
// 验证WebSocket配置
if (config.websocket && config.websocket.enabled) {
if (!config.websocket.url) {
errors.push('WebSocket URL不能为空');
} else if (!isValidWebSocketUrl(config.websocket.url)) {
errors.push('WebSocket URL格式不正确');
}
if (config.websocket.heartbeat && (config.websocket.heartbeat < 1 || config.websocket.heartbeat > 300)) {
errors.push('WebSocket心跳间隔应在1-300秒之间');
}
}
// 验证MQTT配置
if (config.mqtt && config.mqtt.enabled) {
if (!config.mqtt.url) {
errors.push('MQTT URL不能为空');
} else if (!isValidMQTTUrl(config.mqtt.url)) {
errors.push('MQTT URL格式不正确');
}
if (!config.mqtt.clientId) {
errors.push('MQTT客户端ID不能为空');
}
if (config.mqtt.qos && (config.mqtt.qos < 0 || config.mqtt.qos > 2)) {
errors.push('MQTT QoS等级应为0、1或2');
}
}
// 验证HTTP配置
if (config.http && Array.isArray(config.http)) {
config.http.forEach((http, index) => {
if (http.enabled) {
if (!http.url) {
errors.push(`HTTP配置${index + 1}的URL不能为空`);
} else if (!isValidHttpUrl(http.url)) {
errors.push(`HTTP配置${index + 1}的URL格式不正确`);
}
if (http.interval && (http.interval < 1 || http.interval > 3600)) {
errors.push(`HTTP配置${index + 1}的轮询间隔应在1-3600秒之间`);
}
}
});
}
return errors;
}
function isValidWebSocketUrl(url) {
return url.startsWith('ws://') || url.startsWith('wss://');
}
function isValidMQTTUrl(url) {
return url.startsWith('ws://') || url.startsWith('wss://') || url.startsWith('mqtt://') || url.startsWith('mqtts://');
}
function isValidHttpUrl(url) {
return url.startsWith('http://') || url.startsWith('https://');
}
6. 故障排查
6.1 连接问题诊断
6.1.1 通用诊断步骤
- 检查浏览器控制台 - 查看JavaScript错误和网络请求状态
- 验证配置参数 - 确认地址、端口、认证信息正确
- 测试网络连接 - 使用浏览器开发者工具检查网络连通性
- 查看服务器状态 - 确认服务器正常运行且端口开放
6.1.2 连接状态检查
javascript
// 检查通信连接状态
function checkCommunicationStatus() {
const status = communicationManager.getStatus();
console.log('Communication status:', status);
// 显示状态到UI
updateStatusDisplay(status);
return status;
}
// 定期检查状态
setInterval(checkCommunicationStatus, 10000);
6.2 WebSocket连接问题
6.2.1 常见错误及解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接被拒绝 | 服务器未运行 | 启动WebSocket服务器 |
| 跨域错误 | CORS配置问题 | 配置服务器CORS策略 |
| 协议错误 | URL格式错误 | 使用ws://或wss://协议 |
| 端口被阻止 | 防火墙限制 | 开放相应端口 |
6.2.2 连接测试
javascript
// 测试WebSocket连接
function testWebSocketConnection(url) {
return new Promise((resolve, reject) => {
const ws = new WebSocket(url);
const timeout = setTimeout(() => {
ws.close();
reject(new Error('Connection timeout'));
}, 5000);
ws.onopen = () => {
clearTimeout(timeout);
ws.close();
resolve(true);
};
ws.onerror = (error) => {
clearTimeout(timeout);
ws.close();
reject(error);
};
});
}
// 使用示例
testWebSocketConnection('ws://localhost:8080/ws')
.then(() => console.log('WebSocket连接正常'))
.catch(error => console.error('WebSocket连接失败:', error));
6.3 MQTT连接问题
6.3.1 常见错误及解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 服务器地址错误 | 检查MQTT地址是否使用ws://协议 |
| 认证失败 | 用户名/密码错误 | 验证认证信息是否正确 |
| 库未加载 | MQTT.js未引入 | 检查MQTT.js库是否正确加载 |
| 主题未收到 | 订阅主题不匹配 | 确认发布和订阅主题一致 |
6.3.2 诊断代码
javascript
// 检查MQTT库是否加载
function checkMQTTLibrary() {
if (typeof mqtt === 'undefined') {
console.error('MQTT.js库未加载,请检查脚本引入');
return false;
}
if (typeof mqtt.connect !== 'function') {
console.error('MQTT.js库版本不兼容');
return false;
}
console.log('MQTT.js库加载正常');
return true;
}
// 测试MQTT连接
function testMQTTConnection(config) {
return new Promise((resolve, reject) => {
if (!checkMQTTLibrary()) {
reject(new Error('MQTT库未正确加载'));
return;
}
const client = mqtt.connect(config.url, {
clientId: config.clientId,
username: config.username,
password: config.password,
connectTimeout: 5000
});
client.on('connect', () => {
client.end();
resolve(true);
});
client.on('error', (error) => {
client.end();
reject(error);
});
});
}
6.4 HTTP请求问题
6.4.1 常见错误及解决方案
| 错误代码 | 说明 | 解决方案 |
|---|---|---|
| 404 | 地址不存在 | 检查API地址是否正确 |
| 401 | 未授权 | 检查认证信息 |
| 403 | 禁止访问 | 检查用户权限 |
| CORS错误 | 跨域问题 | 配置服务器CORS策略 |
| 500 | 服务器错误 | 检查服务器日志 |
| 超时 | 网络延迟 | 增加超时时间 |
7. 性能优化
7.1 WebSocket性能优化
7.1.1 最佳实践
- 合理设置心跳间隔 - 心跳间隔过长会影响断线检测,过短会增加服务器负担,建议设置为10-30秒
- 消息压缩 - 对于大型消息,可使用压缩算法减少网络传输量
- 批量发送 - 将多个小消息合并为一个大消息发送,减少网络开销
- 连接池管理 - 对于多个场景,考虑使用连接池共享WebSocket连接
- 断线重连策略 - 实现指数退避重连,避免频繁重连导致服务器过载
7.1.2 代码优化
javascript
// WebSocket客户端优化
class OptimizedWebSocketClient extends WebSocketClient {
constructor(url, options = {}) {
super(url, options);
this.messageQueue = [];
this.batchInterval = null;
this.batchSize = 50;
this.batchTimeout = 100;
}
// 批量发送消息
sendBatch(messages) {
if (messages.length === 0) return;
const batchMessage = {
MESSAGETYPE: "06", // 批量消息
MESSAGECONTENT: messages
};
super.send(batchMessage);
}
// 队列消息,自动批量发送
queueMessage(message) {
this.messageQueue.push(message);
if (this.messageQueue.length >= this.batchSize) {
this.flushQueue();
} else if (!this.batchInterval) {
this.batchInterval = setTimeout(() => {
this.flushQueue();
}, this.batchTimeout);
}
}
flushQueue() {
if (this.batchInterval) {
clearTimeout(this.batchInterval);
this.batchInterval = null;
}
if (this.messageQueue.length > 0) {
this.sendBatch([...this.messageQueue]);
this.messageQueue = [];
}
}
}
7.2 MQTT性能优化
7.2.1 最佳实践
- 合理选择QoS等级 - 根据业务需求选择合适的QoS等级,避免过度使用QoS 2
- 主题设计 - 使用层次化的主题结构,避免使用通配符订阅大量主题
- 消息过滤 - 在客户端实现消息过滤,减少不必要的处理
- 连接管理 - 实现连接池,避免频繁创建和销毁MQTT连接
- 断线重连 - 实现智能重连策略,避免网络波动时的频繁重连
7.2.2 代码优化
javascript
// MQTT客户端优化
class OptimizedMQTTClient extends MQTTClient {
constructor(config) {
super(config);
this.messageBuffer = new Map();
this.bufferTimeout = 500; // 500ms缓冲
this.bufferTimers = new Map();
}
// 智能消息缓冲
publishWithBuffer(topic, message, options = {}) {
const bufferKey = `${topic}:${JSON.stringify(options)}`;
// 清除之前的定时器
if (this.bufferTimers.has(bufferKey)) {
clearTimeout(this.bufferTimers.get(bufferKey));
}
// 缓冲消息
this.messageBuffer.set(bufferKey, message);
// 设置新的定时器
this.bufferTimers.set(bufferKey, setTimeout(() => {
if (this.messageBuffer.has(bufferKey)) {
const bufferedMessage = this.messageBuffer.get(bufferKey);
super.publish(topic, bufferedMessage, options);
this.messageBuffer.delete(bufferKey);
this.bufferTimers.delete(bufferKey);
}
}, this.bufferTimeout));
}
}
7.3 HTTP性能优化
7.3.1 最佳实践
- 合理设置轮询间隔 - 根据数据更新频率设置合适的轮询间隔,避免过于频繁的请求
- 缓存策略 - 实现客户端缓存,减少重复请求
- 批量请求 - 将多个API请求合并为一个,减少网络开销
- 请求节流 - 实现请求节流,避免短时间内发送大量请求
- 错误处理 - 实现智能错误重试策略,避免无意义的重试
7.3.2 代码优化
javascript
// HTTP客户端优化
class OptimizedHTTPClient extends HTTPClient {
constructor(config) {
super(config);
this.requestThrottle = null;
this.throttleDelay = 100;
}
// 节流请求
async throttledRequest(options = {}) {
return new Promise((resolve, reject) => {
if (this.requestThrottle) {
clearTimeout(this.requestThrottle);
}
this.requestThrottle = setTimeout(async () => {
try {
const result = await this.request(options);
resolve(result);
} catch (error) {
reject(error);
}
}, this.throttleDelay);
});
}
// 批量请求
async batchRequests(requests) {
const results = [];
// 并发请求但限制数量
const maxConcurrent = 3;
let currentIndex = 0;
while (currentIndex < requests.length) {
const batch = requests.slice(currentIndex, currentIndex + maxConcurrent);
const batchResults = await Promise.all(
batch.map(req => this.request(req).catch(error => ({ error })))
);
results.push(...batchResults);
currentIndex += maxConcurrent;
}
return results;
}
}
7.4 通用性能优化
7.4.1 网络优化
- 使用HTTPS - 保证数据传输安全的同时,现代浏览器对HTTPS有性能优化
- CDN加速 - 对于静态资源使用CDN加速
- GZIP压缩 - 启用服务器端GZIP压缩,减少传输数据量
- HTTP/2 - 启用HTTP/2,支持多路复用和服务器推送
7.4.2 客户端优化
- 数据处理优化 - 优化数据处理逻辑,避免复杂的计算
- 内存管理 - 及时清理不需要的对象,避免内存泄漏
- 事件处理 - 优化事件监听器,避免内存泄漏
- UI更新 - 批量更新UI,避免频繁DOM操作
8. 安全考虑
8.1 WebSocket安全
8.1.1 安全配置
- 使用WSS - 生产环境必须使用WSS(WebSocket Secure)协议
- 认证机制 - 实现基于token的WebSocket认证
- 消息加密 - 对敏感消息进行加密传输
- 连接限制 - 限制单个IP的连接数,防止DoS攻击
- 消息验证 - 验证消息格式和内容,防止注入攻击
8.1.2 安全实现
javascript
// WebSocket安全认证
class SecureWebSocketClient extends WebSocketClient {
constructor(url, options = {}) {
super(url, options);
this.token = options.token;
}
connect() {
// 添加认证参数
const urlWithAuth = new URL(this.url);
if (this.token) {
urlWithAuth.searchParams.append('token', this.token);
}
this.url = urlWithAuth.toString();
super.connect();
}
// 加密消息
encryptMessage(message) {
// 这里实现消息加密逻辑
return message;
}
// 解密消息
decryptMessage(message) {
// 这里实现消息解密逻辑
return message;
}
send(data) {
const encryptedData = this.encryptMessage(data);
super.send(encryptedData);
}
handleMessage(event) {
try {
const encryptedData = JSON.parse(event.data);
const decryptedData = this.decryptMessage(encryptedData);
// 验证消息格式
if (!this.validateMessage(decryptedData)) {
console.warn('Invalid message format');
return;
}
// 处理解密后的消息
super.handleMessage({ data: JSON.stringify(decryptedData) });
} catch (error) {
console.error('Message processing error:', error);
}
}
validateMessage(message) {
// 验证消息格式和内容
return message && typeof message === 'object';
}
}
8.2 MQTT安全
8.2.1 安全配置
- 使用TLS - 生产环境使用MQTTS(MQTT over TLS)
- 强密码策略 - 使用强密码和证书认证
- 主题访问控制 - 实现细粒度的主题访问控制
- 客户端认证 - 实现基于证书的客户端认证
- 消息加密 - 对敏感消息进行端到端加密
8.2.2 安全实现
javascript
// MQTT安全配置
const secureMQTTConfig = {
url: 'wss://mqtt.example.com:8883', // 使用WSS
clientId: `mqtt_client_${Date.now()}`,
username: 'secure_user',
password: 'strong_password',
protocol: 'mqtts', // 使用TLS
rejectUnauthorized: true, // 验证服务器证书
cert: fs.readFileSync('./client.crt'), // 客户端证书
key: fs.readFileSync('./client.key'), // 客户端密钥
ca: [fs.readFileSync('./ca.crt')] // CA证书
};
8.3 HTTP安全
8.3.1 安全配置
- 使用HTTPS - 生产环境必须使用HTTPS
- 认证授权 - 实现基于token的认证机制
- 请求验证 - 验证请求参数和头信息
- CORS配置 - 正确配置CORS策略,避免跨域攻击
- 防CSRF - 实现CSRF保护机制
- 防XSS - 对输入和输出进行适当的编码
8.3.2 安全实现
javascript
// HTTP安全请求
class SecureHTTPClient extends HTTPClient {
constructor(config) {
super(config);
this.token = config.token;
this.csrfToken = config.csrfToken;
}
buildHeaders(config) {
const headers = super.buildHeaders(config);
// 添加CSRF令牌
if (this.csrfToken) {
headers['X-CSRF-Token'] = this.csrfToken;
}
return headers;
}
async request(options = {}) {
// 验证请求参数
if (!this.validateRequest(options)) {
throw new Error('Invalid request parameters');
}
try {
const result = await super.request(options);
// 验证响应数据
if (!this.validateResponse(result)) {
throw new Error('Invalid response data');
}
return result;
} catch (error) {
// 处理安全相关错误
if (error.response && error.response.status === 401) {
// 处理认证失败
this.handleAuthFailure();
}
throw error;
}
}
validateRequest(options) {
// 验证请求参数
return true;
}
validateResponse(response) {
// 验证响应数据
return true;
}
handleAuthFailure() {
// 处理认证失败逻辑
console.error('Authentication failed');
}
}
8.4 安全最佳实践
- 定期更新依赖 - 定期更新通信库和依赖包,修复安全漏洞
- 安全审计 - 定期进行安全审计,发现并修复安全问题
- 监控告警 - 实现安全事件监控和告警机制
- 安全文档 - 建立安全配置文档和最佳实践指南
- 培训教育 - 对开发人员进行安全培训,提高安全意识
9. 高级配置
9.1 混合通信模式
系统支持同时使用多种通信方式,根据不同的数据类型和场景需求选择合适的通信方式:
- 实时控制 - 使用WebSocket,确保低延迟
- 批量数据 - 使用HTTP,减少连接开销
- 设备通信 - 使用MQTT,适合IoT设备
9.1.1 混合配置示例
javascript
// 混合通信配置
const hybridCommunicationConfig = {
// 实时控制数据 - WebSocket
websocket: {
enabled: true,
url: 'wss://example.com/ws',
topics: ['control', 'status']
},
// 批量数据 - HTTP
http: [
{
id: 'batch_data',
enabled: true,
url: 'https://example.com/api/batch',
interval: 60 // 每分钟一次
}
],
// IoT设备数据 - MQTT
mqtt: {
enabled: true,
url: 'wss://mqtt.example.com',
topic: '/devices/#',
qos: 1
}
};
9.2 自定义通信适配器
系统支持自定义通信适配器,实现特定场景的通信需求:
9.2.1 适配器接口
javascript
// 通信适配器接口
class CommunicationAdapter {
constructor(config) {
this.config = config;
}
// 初始化
init() {}
// 连接
connect() {}
// 断开连接
disconnect() {}
// 发送数据
send(data) {}
// 接收数据
onData(callback) {}
// 错误处理
onError(callback) {}
// 获取状态
getStatus() {}
}
9.2.2 自定义适配器示例
javascript
// 自定义通信适配器示例
class CustomCommunicationAdapter extends CommunicationAdapter {
constructor(config) {
super(config);
this.connected = false;
}
init() {
console.log('Custom adapter initialized');
}
connect() {
// 实现自定义连接逻辑
this.connected = true;
console.log('Custom adapter connected');
}
disconnect() {
// 实现自定义断开逻辑
this.connected = false;
console.log('Custom adapter disconnected');
}
send(data) {
// 实现自定义发送逻辑
console.log('Sending data:', data);
}
onData(callback) {
// 实现自定义数据接收逻辑
this.dataCallback = callback;
}
onError(callback) {
// 实现自定义错误处理逻辑
this.errorCallback = callback;
}
getStatus() {
return {
connected: this.connected,
type: 'custom'
};
}
}
10. 常见问题解答
10.1 连接问题
Q: WebSocket连接总是断开怎么办?
A: 检查网络稳定性,调整心跳间隔,实现自动重连机制,确保服务器端配置正确。
Q: MQTT连接失败提示认证错误?
A: 检查用户名和密码是否正确,确认MQTT服务器是否启用了认证,验证客户端ID是否唯一。
Q: HTTP请求返回403错误?
A: 检查API权限配置,确认认证信息是否正确,验证CORS策略是否允许跨域请求。
10.2 性能问题
Q: 实时数据更新卡顿怎么办?
A: 优化数据处理逻辑,减少DOM操作,使用批量更新,考虑使用Web Worker处理复杂计算。
Q: 多个场景同时运行时性能下降?
A: 实现连接池,共享通信连接,优化数据处理,考虑使用防抖和节流技术。
Q: 网络延迟高如何优化?
A: 使用CDN加速,优化服务器响应时间,实现数据压缩,考虑边缘计算。
10.3 安全问题
Q: 如何防止WebSocket连接被恶意攻击?
A: 使用WSS协议,实现基于token的认证,限制连接频率,验证消息格式。
Q: MQTT主题被未授权访问怎么办?
A: 实现主题访问控制,使用强密码,启用TLS加密,定期轮换证书。
Q: HTTP API如何防止CSRF攻击?
A: 实现CSRF令牌,验证Origin头,使用SameSite cookie属性,正确配置CORS策略。
10.4 配置问题
Q: 如何选择合适的通信方式?
A: 根据数据更新频率、实时性要求、网络环境等因素选择:WebSocket适合高频实时数据,MQTT适合IoT设备,HTTP适合低频数据和兼容性要求高的场景。
Q: 如何配置多数据源?
A: 使用HTTP管理器添加多个HTTP配置,每个配置独立运行,支持不同的API地址和参数。
Q: 通信配置如何同步到所有场景?
A: 可以在全局配置中设置默认通信参数,场景级配置会覆盖全局配置。
立即体验
👉 演示地址: http://www.ricon.cloud:81
🌐 官网地址: http://www.ricon.cloud