Angular应用连接Socket时无限加载无报错,求解决方案
问题核心
你的问题根源是协议不兼容:Angular用的ngx-socket-io基于Socket.IO协议实现,而Python端的websockets库是标准WebSocket协议,两者的握手流程、消息格式完全不同,导致Angular端连接一直处于pending状态,页面卡死。
解决方案一:Python端改用Socket.IO库(推荐,适配现有Angular代码)
1. 安装依赖
pip install python-socketio python-engineio asyncio uvicorn
2. 修改Python服务端代码
import asyncio import socketio # 初始化Socket.IO服务,允许跨域(生产环境请指定具体域名) sio = socketio.AsyncServer(cors_allowed_origins="*") app = socketio.ASGIApp(sio) # 监听连接事件 @sio.event async def connect(sid, environ): print(f"客户端 {sid} 已连接") # 监听Angular发送的message事件 @sio.event async def message(sid, data): print("收到消息:", data) # 如需广播给所有客户端,取消下面注释: # await sio.emit('message', data) # 监听断开连接事件 @sio.event async def disconnect(sid): print(f"客户端 {sid} 已断开") async def main(): await asyncio.create_task(uvicorn.run(app, host="localhost", port=8988)) if __name__ == "__main__": asyncio.run(main())
3. 调整Angular的Socket服务
去掉手动调用的connect()(ngx-socket-io会自动处理连接),增加状态监听便于排查问题:
import { Injectable } from '@angular/core'; import { Socket } from 'ngx-socket-io'; @Injectable() export class BoardSessionSocketService { constructor(private socket: Socket) { // 监听连接状态 this.socket.on('connect', () => console.log('Socket连接成功')); this.socket.on('disconnect', () => console.log('Socket连接断开')); this.socket.on('connect_error', (err) => console.error('Socket连接失败:', err)); } sendMessage(msg: string) { this.socket.emit('message', msg); } }
解决方案二:Angular端改用原生WebSocket API(不修改Python服务)
如果不想更换Python的websockets库,直接用原生WebSocket重写Angular服务:
1. 重写Socket服务
import { Injectable } from '@angular/core'; @Injectable() export class BoardSessionSocketService { private socket: WebSocket | null = null; constructor() { this.initSocket(); } private initSocket() { this.socket = new WebSocket('ws://localhost:8988'); // 连接成功回调 this.socket.onopen = () => { console.log('WebSocket连接成功'); this.sendMessage("Hello, this is angular"); }; // 错误回调 this.socket.onerror = (error) => console.error('WebSocket连接错误:', error); // 断开连接回调,自动重连 this.socket.onclose = () => { console.log('WebSocket连接关闭,3秒后尝试重连'); setTimeout(() => this.initSocket(), 3000); }; } sendMessage(msg: string) { if (this.socket && this.socket.readyState === WebSocket.OPEN) { this.socket.send(msg); } else { console.warn('WebSocket未连接,无法发送消息'); } } }
2. 清理Angular模块配置
删除app.module.ts中ngx-socket-io相关代码:
// 移除以下两行 // import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io'; // const config: SocketIoConfig = { url: 'http://localhost:8988', options: {} }; @NgModule({ declarations: [], imports: [ // 移除 SocketIoModule.forRoot(config) ], providers: [ BoardSessionSocketService, provideClientHydration() ], bootstrap: [AppComponent] }) export class AppModule { }
3. 调整组件发送时机
避免在构造函数直接发消息(原生WebSocket连接是异步的),可以移到ngOnInit或用户触发事件:
import { Component, Input, OnInit } from '@angular/core'; import { Note } from '../board.component'; import { BoardSessionSocketService } from '../../services/board-session-socket.service'; @Component({ selector: 'app-column', templateUrl: './column.component.html', styleUrl: './column.component.less' }) export class ColumnComponent implements OnInit { @Input() columnTitle:string = "" @Input() notes:Note[] = [] constructor(private boardSocket: BoardSessionSocketService) { } ngOnInit(): void { // 如需手动触发,取消下面注释(服务中已在连接成功后发送,可根据需求选择) // this.boardSocket.sendMessage("Hello, this is angular") } }
4. Python端添加跨域支持
如果Angular运行在http://localhost:4200,修改Python服务端代码允许跨域:
async def main(): async with websockets.serve( echo, "localhost", 8988, extra_headers={ "Access-Control-Allow-Origin": "http://localhost:4200", "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type" } ): await asyncio.Future() # 保持服务运行 asyncio.run(main())
内容的提问来源于stack exchange,提问作者Fergus O'H
相关产品推荐
相关产品推荐

