You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 15:18:06