传统实现方式:前端轮询获取、websocket
前端轮询
在前端定时轮询获取后台服务数据,然后进行页面渲染
- 优点:实现方式简单
- 缺点:存在数据延迟; 频繁创建 / 销毁网络连接会增加性能开销和网络带宽
websocket
- 优点:功能强大、完全实用
- 缺点:笨重
SSE(Server-Sent Events)
SSE 是基于 HTTP 长链接的服务端主动推送技术
- 技术定义: 基于 HTTP 长链接实现的服务端主动向客户端推送消息的技术
- 技术原理: 依托 HTTP 1.1 的分块传输编码机制 (Transfer-Encodingchunked),允许服务器分批次向客户端发送数据
- 核心优势: 复用长链接,避免客户端频繁创建 / 销毁连接,服务端数据变化时直接推送
// 后端代码
val clientsMap =mutableMap0f<String,SseEmitter>()
@GetMapping("/subscribe-data",produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
fun subscribe(): SseEmitter {val emitter=SseEmitter(timeout:5*60*1000L)
val clientId = RandomUtil.uuid()
clientsMap[clientId]=emitter
emitter.onCompletion {Logger.error("sse 结束")
clientsMap.remove(clientId)
}
emitter.onTimeout {logger.error("sse 超时")
clientsMap.remove(clientId)
}
emitter.onError { it: Throwable!
logger.error("sse 异常")
clientsMap.remove(clientId)
}
return emitter
}
// 前端代码
// 创建 EventSource 对象,建立 SSE 连接
const eventSource = new EventSource(`${baseUrl}/api/subscribe-data`);
// 连接成功
eventSource.onopen=()=>{console.log("连接成功。.success");
}
// 监听特定事件 - 游戏数据
eventSource.addEventListener('data_update',(event)=>{console.log('收到消息 data update:',event.data);
// 更新页面
});
后端数据发生变化
// 在数据变化的地方调用发送方法
fun sendOne(clientId: String, sse: SseEmitter, eventName: String, data: Map<String,Any?>): Boolean {
try {sse.send(SseEmitter.event().name(eventName).data(data))
return true
}catch(e:I0xception){logger.warn("连接已关闭,event_name={},data=}",eventName,data,e)
clientsMap.remove(clientId)
}catch(e:Exception){logger.error("推送消息失败,event_name={},data=}",eventName, data,e)
}
return false
}
// 推送给所有人
fun sendAll(eventName:String,data:Map<String,Any?>){for(item in this.clientsMap.entries){sendOne(item.key,item.value,eventName,data)
}
}
正文完
发表至: PM
2025-09-23