一、核心差异:WebSocket vs HTTP
特性 | HTTP | WebSocket |
---|---|---|
连接方式 | 短连接 (请求-响应后断开) | 长连接 (持久化双向通道) |
通信方向 | 单向 (客户端发起请求) | 双向 (服务端可主动推送) |
协议开销 | 每次请求携带完整 HTTP 头 | 初始握手后仅传输数据 |
实时性 | 低 (依赖轮询) | 高 (毫秒级延迟) |
适用场景 | 静态资源、API 请求 | 实时聊天、股票行情、协同编辑 |
关键区别:WebSocket 通过一次 HTTP 握手升级为全双工 TCP 连接,实现服务端主动推送能力,突破 HTTP 单向通信的限制。
二、Spring Boot 中的 WebSocket 配置
1. 添加依赖 (pom.xml
)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 配置类注册 Bean
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter(); // 自动注册@ServerEndpoint注解
}
}
三、WebSocket 服务端实现
@Component
@ServerEndpoint("/ws/{sid}") // 定义WebSocket终结点路径
public class WebSocketServer {
// 存储会话ID与Session对象的映射
private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
/**
* 连接建立成功时调用
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
sessionMap.put(sid, session);
System.out.println("🚀 客户端连接: " + sid + " | 当前连接数: " + sessionMap.size());
}
/**
* 收到客户端消息时调用
*/
@OnMessage
public void onMessage(String message, @PathParam("sid") String sid) {
System.out.println("📩 收到消息 [" + sid + "]: " + message);
// 实现业务逻辑处理
}
/**
* 连接关闭时调用
*/
@OnClose
public void onClose(@PathParam("sid") String sid) {
sessionMap.remove(sid);
System.out.println("❌ 连接关闭: " + sid);
}
/**
* 向所有客户端广播消息
*/
public void sendToAllClient(String message) {
sessionMap.forEach((sid, session) -> {
try {
if (session.isOpen()) {
session.getBasicRemote().sendText(message);
}
} catch (IOException e) {
System.err.println("发送消息失败: " + e.getMessage());
}
});
}
}
四、结合定时任务实现服务端主动推送
@Component
public class WebSocketTask {
@Autowired
private WebSocketServer webSocketServer;
/**
* 每5秒向所有客户端推送服务器时间
*/
@Scheduled(fixedRate = 5000)
public void sendServerTime() {
String timeMsg = "服务器时间: " +
LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
webSocketServer.sendToAllClient(timeMsg);
}
/**
* 每天8:30推送业务报表
*/
@Scheduled(cron = "0 30 8 * * ?")
public void sendDailyReport() {
String report = generateDailyReport(); // 生成报表的业务方法
webSocketServer.sendToAllClient(report);
}
}
五、客户端连接示例 (JavaScript)
<script>
const socket = new WebSocket('ws://your-domain.com/ws/user123');
// 监听连接建立
socket.onopen = () => {
console.log('WebSocket连接已建立');
socket.send('客户端就绪'); // 发送初始消息
};
// 接收服务端消息
socket.onmessage = (event) => {
console.log('收到服务端消息:', event.data);
// 更新UI显示
};
// 监听连接关闭
socket.onclose = () => {
console.log('WebSocket连接已关闭');
};
</script>
六、生产环境最佳实践
连接管理优化
// 使用线程安全集合
private static final ConcurrentMap<String, Session> sessions =
new ConcurrentHashMap<>();
// 添加心跳检测机制
@OnMessage
public void onPong(PongMessage pong, @PathParam("sid") String sid) {
// 处理心跳响应
}
消息压缩配置
# application.properties
server.compression.enabled=true
server.compression.mime-types=text/plain,text/html,application/json
安全加固
// 拦截器验证Token
public class AuthInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ...) {
String token = ((ServletServerHttpRequest) request).getServletRequest().getParameter("token");
return isValidToken(token); // 自定义验证逻辑
}
}
集群支持方案
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 使用RabbitMQ作为消息代理
config.enableStompBrokerRelay("/topic")
.setRelayHost("rabbitmq-host");
}
}
七、典型应用场景
实时监控系统
服务器状态实时推送
业务指标动态更新
协同办公工具
文档协同编辑
实时白板共享
金融交易系统
股价实时波动推送
交易指令即时执行
物联网(IoT)
设备状态实时上报
远程控制指令下发
性能对比:在 1000 并发连接下,WebSocket 比 HTTP 长轮询节省 95% 的带宽,降低 80% 的延迟(数据来源:WebSocket.org 基准测试)
通过 Spring Boot 的简洁实现,WebSocket 为现代 Web 应用提供了真正的实时双向通信能力,完美解决了 HTTP 协议在实时交互场景中的局限性。