Angular通过SockJS连接Spring Boot WebSocket报错及仅首次连接生效问题
问题解决方案
一、修复Spring Boot WebSocket配置
你当前的服务端配置存在两处会导致握手失败的问题,按以下方式调整:
- 消息代理路径不要使用根路径
/,避免和应用接口路径冲突,同时补充应用目标前缀,规范消息路由规则 - 高版本Spring Boot(2.4+)中
setAllowedOrigins对SockJS的跨域校验存在兼容问题,替换为setAllowedOriginPatterns - 确保
UserHandshakeHandler中正确读取请求参数中的token完成身份校验,不要直接抛出未授权异常
修改后的配置代码如下:
@Override public void configureMessageBroker(MessageBrokerRegistry config) { // 配置消息代理支持的路径前缀,按需保留即可 config.enableSimpleBroker("/topic", "/queue"); config.setUserDestinationPrefix("/user"); // 放开应用目标前缀配置,规范客户端发送消息的路径 config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws") // 替换为允许的跨域规则,支持通配符 .setAllowedOriginPatterns("http://localhost:4200") .setHandshakeHandler(new UserHandshakeHandler()) .withSockJS(); // 如果需要支持原生WebSocket连接,新增无SockJS的端点配置 registry.addEndpoint("/ws/native") .setAllowedOriginPatterns("http://localhost:4200") .setHandshakeHandler(new UserHandshakeHandler()); } @Override public boolean configureMessageConverters(List<MessageConverter> messageConverters) { DefaultContentTypeResolver resolver = new DefaultContentTypeResolver(); resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON); MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); converter.setObjectMapper(new ObjectMapper()); converter.setContentTypeResolver(resolver); messageConverters.add(converter); return false; }
二、修复Angular前端连接逻辑
你当前的逻辑没有处理旧连接销毁,这是后续连接失败的核心原因,按以下方式调整:
- 新建连接前先判断是否存在活跃的STOMP客户端,先断开销毁旧实例,避免残留连接占用资源
- 增加错误回调和断开重连逻辑,避免连接异常后无法恢复
修改后的连接代码如下:
// 先销毁旧连接 if (this.stompClient?.connected) { this.stompClient.disconnect(() => { this.stompClient = null; this.socket = null; }); } // 新建连接 this.socket = new SockJS(environment.serverUrl + socketPrefix + '?token=' + this.authService.getAccessToken()); this.stompClient = Stomp.over(this.socket); // 生产环境可以关闭STOMP的调试日志 this.stompClient.debug = () => {}; this.stompClient.connect({}, () => { this.stompClient.subscribe(hubMethodSubscription.noteTextUpdate, (data: any) => { console.error(data); this.observableUpdateNoteText.next(JSON.parse(data.body)); }); this.stompClient.subscribe(hubMethodSubscription.deleteNoteFromOwner, (data: any) => { console.error(data); this.observableDeleteNoteFromOwner.next(JSON.parse(data.body)); }); this.stompClient.subscribe(hubMethodSubscription.sendNewNotificationKek, (data: any) => { console.error(data); }); }, (error) => { // 连接失败触发重连逻辑,可加延迟避免频繁请求 setTimeout(() => this.initWebSocket(), 3000); });
三、原生WebSocket仅首次连接正常的问题修复
原生WebSocket无法直接连接开启了withSockJS()的端点,SockJS端点有专属的握手协议,首次连接可能走了兼容逻辑,后续就会失效。按上述服务端配置新增原生WebSocket专属端点/ws/native后,前端原生WS连接直接访问该端点即可。
内容的提问来源于stack exchange,提问作者Dmitry Bogomaz
相关产品推荐
相关产品推荐

