主题
7.3 前端接入示例
一个完整的、可直接改用的原生 JavaScript 接入示例,包含协议自适应、订阅、断线重连、重新订阅。
7.3.1 完整示例
html
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>LPPLC 实时数据</title></head>
<body>
<p>温度:<span id="车间1/1号机/温度">--</span> ℃</p>
<p>湿度:<span id="车间1/1号机/湿度">--</span> %</p>
<script>
const CONFIG = {
username: 'linpan',
password: '你的密码',
project: 'main',
datas: ['车间1/1号机/温度', '车间1/1号机/湿度'],
}
let ws = null
let retry = 0
function connect() {
// 按当前页面协议自动选择 ws / wss
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'
ws = new WebSocket(`${protocol}//${location.host}/ws`)
ws.onopen = () => {
retry = 0
// 连上后立即发送订阅(认证信息在报文里,不在 URL 上)
ws.send(JSON.stringify({ cmd: 'subscribe', ...CONFIG }))
}
ws.onmessage = (e) => {
let list
try { list = JSON.parse(e.data) } catch { return }
if (!Array.isArray(list)) return
// 推送是数组,元素为 {name, value}
list.forEach(({ name, value }) => {
const el = document.getElementById(name)
if (el) el.textContent = value
})
}
ws.onclose = () => scheduleReconnect()
ws.onerror = () => { try { ws.close() } catch {} }
}
function scheduleReconnect() {
// 指数退避,上限 30 秒,避免服务器重启时集体冲击
const delay = Math.min(1000 * 2 ** retry, 30000)
retry++
setTimeout(connect, delay)
}
connect()
</script>
</body>
</html>7.3.2 关键点
- 协议自适应:HTTPS 页面必须用
wss://,HTTP 页面用ws://,不能写死 - 认证在报文里:连接 URL 是干净的
/ws,不带?token=;账号密码放在subscribe报文中 - 推送是数组:
onmessage里先判断Array.isArray,再遍历取name/value - 重连后要重新订阅:
onopen里每次都发subscribe,不要只在第一次发 - 退避重连:固定间隔重连会在服务器重启时形成风暴,用指数退避
7.3.3 写数据(控制类界面)
WebSocket 只收不发业务写入。界面上要控制设备,用 HTTP 的 set_real:
javascript
async function setPoint(name, value) {
const resp = await fetch(`${location.origin}/web`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
cmd: 'set_real',
username: CONFIG.username,
password: CONFIG.password,
project: CONFIG.project,
data: [{ name, value: String(value) }],
}),
})
const r = await resp.json()
if (r.cmdreq !== 'ok') throw new Error('写入失败: ' + r.cmdreq)
}
// 例:远程启动
// setPoint('车间1/1号机/启停', 1)写入后短时间内 WebSocket 可能还会推来旧值,控制类控件要做写保护(见 7.2 第 7.2.5 节)。
7.3.4 生产环境提醒
- 账号密码会出现在前端代码里,不要用主账号,给页面单独开一个只读或最小权限的子账号
- 页面走 HTTPS,WebSocket 自然走 WSS。TLS 只保证传输途中不被偷看,请求体里的账号密码本身仍是明文字段,所以任何能看到这份前端代码的人都能拿到它——这正是上一条要求单独开子账号的原因
- 如需完善的重连、心跳、状态管理,可参考云组态运行画面自己的重连与心跳实现思路