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

Angular与Spring Boot Socket.IO通信异常问题求助

Angular与Spring Boot Socket.IO通信异常排查与解决

问题现象

  • Spring Boot日志显示Angular端频繁触发连接、断开事件
  • Angular控制台报错Socket is not connected, cannot send message!
  • 浏览器Socket连接请求URL未携带room参数
  • 对接Node Mock服务器时通信正常,仅Spring Boot端出现问题

现有代码

Angular服务代码

@Injectable({
providedIn: 'root'
})
export class WebsocketService {

private socket: any;
isBrowser = false;

constructor(@Inject(PLATFORM_ID) private platformId: Object) {
this.isBrowser = isPlatformBrowser(this.platformId)
if (this.isBrowser) {
  console.log("hello")
  this.initSocket();
}
}

private initSocket(): void {
this.socket = io('http://ipv4:8081');

this.socket.on('connect', () => {
  console.log('Connected to Socket.IO server');
});

this.socket.on('disconnect', () => {
  console.log('Disconnected from Socket.IO server');
});

this.socket.on('get_message', (data: any) => {
  // Handle incoming messages from the server
  console.log('Received message:', data);
  // You can emit events or update your application state here
});
}

sendMessage(room: string, message: any): void {

if (this.isBrowser) {

  this.initSocket();
  if (this.socket.connected) {
    this.socket.emit('send_message', { room, message });
  } else {
    console.error('Socket is not connected, cannot send message!');
  }
  } 
  }
  }

Spring Boot应用代码

@Slf4j
@Component
public class SocketIOModule {


private final SocketIOServer server;
private final SocketIOService socketService;

public SocketIOModule(SocketIOServer server, SocketIOService socketService) {
    this.server = server;
    this.socketService = socketService;
    this.server.addConnectListener(onConnected());
    this.server.addDisconnectListener(onDisconnected());
    this.server.addEventListener("send_message", Message.class, onChatReceived());
}

private DataListener<Message> onChatReceived() {
    return (senderClient, data, ackSender) -> {
        log.info("Data: {}",data.toString());
        socketService.sendMessage(data.getRoom(),"get_message", senderClient, data.getMessage());
    };
}

private ConnectListener onConnected() {
    return (client) -> {

        log.info(String.valueOf(client.getHandshakeData()));
        final String roomVariable = client.getHandshakeData().getSingleUrlParam("room");
        final String room = Objects.nonNull(roomVariable)?roomVariable:"temp";
        log.info("Room: {}",room);
        client.joinRoom(room);
        log.info("Socket ID[{}]  Connected to socket", client.getSessionId().toString());
    };
}

private DisconnectListener onDisconnected() {
    return client -> {
        log.info("Client[{}] - Disconnected from socket", client.getSessionId().toString());
    };
}

}

问题根源与修复方案

1. 重复初始化Socket导致频繁断开

Angular的sendMessage方法每次调用都会执行initSocket(),创建新的Socket连接,旧连接被强制断开,引发服务器端频繁的连接/断开日志。

修复代码:

@Injectable({ providedIn: 'root' })
export class WebsocketService {
  private socket: any;
  isBrowser = false;

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {
    this.isBrowser = isPlatformBrowser(this.platformId);
    if (this.isBrowser) {
      this.initSocket();
    }
  }

  private initSocket(room?: string): void {
    // 避免重复初始化已连接的Socket
    if (this.socket?.connected) return;

    // 携带room参数建立连接
    const queryParams = room ? { room } : {};
    this.socket = io('http://ipv4:8081', { query: queryParams });
    
    this.bindSocketListeners();
  }

  // 抽离监听逻辑,避免重复绑定事件
  private bindSocketListeners(): void {
    this.socket.on('connect', () => {
      console.log('Connected to Socket.IO server');
    });

    this.socket.on('disconnect', () => {
      console.log('Disconnected from Socket.IO server');
    });

    this.socket.on('get_message', (data: any) => {
      console.log('Received message:', data);
    });
  }

  sendMessage(room: string, message: any): void {
    if (!this.isBrowser) return;

    // 检查Socket状态,未连接则携带当前room重建连接
    if (!this.socket?.connected) {
      this.initSocket(room);
      // 延迟发送,确保连接建立完成
      setTimeout(() => {
        this.socket.emit('send_message', { room, message });
      }, 500);
    } else {
      this.socket.emit('send_message', { room, message });
    }
  }
}

2. 连接时未携带room参数

Spring Boot端在连接阶段通过URL参数获取room,但原Angular代码初始化Socket时未传递该参数,导致服务器端使用默认的temp房间,同时可能因参数缺失引发连接兼容性问题。

修复:
在initSocket方法中通过query参数传递room信息,如上述修复代码所示,确保连接请求URL携带room参数。

3. Socket.IO版本兼容性问题

Node的Socket.IO服务器与Spring Boot使用的netty-socketio版本可能不匹配,Angular端socket.io-client版本需与服务端版本兼容。

检查与修复:

  • 确认Angular端socket.io-client版本与Spring Boot端netty-socketio版本一致(例如客户端用4.x,服务端也需对应4.x系列)
  • Spring Boot Maven依赖示例:
<dependency>
    <groupId>com.corundumstudio.socketio</groupId>
    <artifactId>netty-socketio</artifactId>
    <version>2.0.11</version> <!-- 需与客户端版本匹配 -->
</dependency>

4. 跨域配置缺失

Spring Boot端未配置正确的跨域规则,导致浏览器拦截Socket连接请求,引发频繁断开。

修复代码:

@Configuration
public class SocketIOConfig {
    @Bean
    public SocketIOServer socketIOServer() {
        Configuration config = new Configuration();
        config.setHostname("0.0.0.0");
        config.setPort(8081);
        // 允许指定域名跨域,生产环境请勿用*
        config.setOrigin("http://your-angular-domain:port");
        return new SocketIOServer(config);
    }
}

内容的提问来源于stack exchange,提问作者kaguya shinomiya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:50:10