WebSocket连接失败:SignalR实时位置共享功能故障求助
SignalR连接一直处于"Connecting"状态排查方案
我正在开发实时位置共享功能,当前使用的SignalR Hub用于推送正在共享位置的用户列表。点击启动按钮后,连接始终卡在"Connecting"状态,新用户共享位置的消息无法被注册。参考聊天功能教程适配了需求,但功能无法正常工作,需要排查问题。
前端代码
share-live.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; import { take } from 'rxjs/operators'; import { MapService } from 'src/app/services/location/map.service'; import { AccountService } from 'src/app/shared/services'; import { ShareLiveService } from '../services/share-live.service'; @Component({ selector: 'app-share-live', templateUrl: './share-live.component.html', styleUrls: ['./share-live.component.scss'] }) export class ShareLiveComponent implements OnDestroy{ userPosition: google.maps.LatLngLiteral = null; username: string; stopWatch = true; connectedToHub = false; isSharing = new BehaviorSubject<boolean>(false); id: number; options: google.maps.MapOptions = { center: {lat: 45.9432, lng: 26.5}, zoom: 16 }; markerOptions: google.maps.MarkerOptions = { clickable: true, draggable: false, }; markerSettings = [ { visible:true, shape:'Circle', fill:'white', width:3, animationDuration:0, border:{width:2,color:'#333'} } ]; constructor( readonly mapService: MapService, private readonly shareLiveService: ShareLiveService, private readonly accountService: AccountService ) { this.accountService.currentUserSource .pipe(take(1)) .subscribe(user => this.username = user.username); this.positionMap(); } ngOnDestroy(): void { if(this.connectedToHub){ this.stopHubConnection(); } } start(): void { this.stopWatch = false; this.isSharing.next(!this.stopWatch); this.connectDisconectHub(); this.id = navigator.geolocation.watchPosition((position) => { console.log(position); this.refreshOptions(position.coords); this.refreshLocation(position.coords); }); } stop(): void { this.stopWatch = true; this.connectDisconectHub(); if(this.id){ navigator.geolocation.clearWatch(this.id); this.id = null; this.isSharing.next(!this.stopWatch); } } private connectDisconectHub(): void { if(!this.connectedToHub){ this.createHubConnection(); } else { this.stopHubConnection(); } } private createHubConnection(): void { this.shareLiveService.createHubConnection(this.username); this.connectedToHub = true; } private stopHubConnection(): void { this.shareLiveService.eraseSharer(this.username) .catch(error=> console.log(error)); this.shareLiveService.stopHubConnection(); this.connectedToHub = false; } private positionMap(): void { navigator.geolocation.getCurrentPosition((position) => { this.refreshOptions(position.coords); }); } private refreshOptions(coordinates: GeolocationCoordinates): void { this.options = { ...this.options, center: {lat: coordinates.latitude, lng: coordinates.longitude} }; } private refreshLocation(coordinates: GeolocationCoordinates): void { this.userPosition = {lat: coordinates.latitude, lng: coordinates.longitude}; } }
share-live.service.ts
import { Injectable } from '@angular/core'; import { HttpTransportType, HubConnection, HubConnectionBuilder } from '@microsoft/signalr'; import { BehaviorSubject, Observable } from 'rxjs'; import { LocationCoords } from 'src/app/shared/types'; import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root' }) export class ShareLiveService { hubUrl = environment.hubUrl; livesharerSource$: Observable<{username: string}[]>; private hubConnection: HubConnection; private livesharer = new BehaviorSubject<{username: string}[]>([]); constructor() { this.livesharerSource$ = this.livesharer.asObservable(); } createHubConnection(username: string): void { this.hubConnection = new HubConnectionBuilder() .withUrl(this.hubUrl + 'locationsharers',{ skipNegotiation: true, transport: HttpTransportType.WebSockets }) .build(); this.hubConnection.start() .then(() => this.sendNewSharer(username)) .catch(error => console.log(error)); } stopHubConnection(): void { if(this.hubConnection){ this.hubConnection.stop() .then(() => console.log('Connection stopped!')) .catch(error => console.log(error)); } } async sendNewSharer(username: string): Promise<any> { return this.hubConnection.invoke('AddNewSharer', username) .catch(error => console.log(error)); } async eraseSharer(username: string): Promise<any> { return this.hubConnection.invoke('RemoveSharer', username) .catch(error => console.log(error)); } }
environment.ts
export const environment = { production: false, url:'https://localhost:5001/api', hubUrl: 'http://localhost:5001/hubs/', mapbox: { accessToken: 'token' } };
后端代码
LiveLocationSharersHub.cs
using DataAccessAPI.DTOs; using DataAccessAPI.Entities; using DataAccessAPI.Interfaces; using Microsoft.AspNetCore.SignalR; namespace DataAccessAPI.SignalR { public class LiveLocationSharersHub : Hub { private readonly ILiveLocationSharersRepository _liveLocationSharersRepository; private readonly ILiveLocationRepository _liveLocationRepository; public LiveLocationSharersHub(ILiveLocationSharersRepository liveLocationSharersRepository, ILiveLocationRepository liveLocationRepository) { _liveLocationSharersRepository = liveLocationSharersRepository; _liveLocationRepository = liveLocationRepository; } public override async Task OnConnectedAsync() { var httpContext = Context.GetHttpContext(); await Groups.AddToGroupAsync(Context.ConnectionId, "people-sharing"); var peopleSharing = _liveLocationSharersRepository.GetAll(); await Clients.Group("people-sharing").SendAsync("PeopleSharingLocation", peopleSharing); } public override async Task OnDisconnectedAsync(Exception exception) { await base.OnDisconnectedAsync(exception); } public async Task AddNewSharer(string username) { if (!await _liveLocationRepository.UserExistsAsync(username)) { throw new HubException("This user doesn't exist! Something is wrong."); } var newSharer = new LiveLocationSharer { Username = username }; _liveLocationSharersRepository.AddSharer(newSharer); if (await _liveLocationRepository.SaveAllAsync()) { await Clients.Group("people-sharing").SendAsync("NewSharer", username); } else { throw new HubException("Something went wrong."); } } public async Task RemoveSharer(string username) { if (!await _liveLocationRepository.UserExistsAsync(username)) { throw new HubException("This user doesn't exist! Something is wrong."); } var sharer = await _liveLocationSharersRepository.GetLiveLocationSharersAsync(username); _liveLocationSharersRepository.Delete(sharer); if (await _liveLocationRepository.SaveAllAsync()) { await Clients.Group("people-sharing").SendAsync("UserDeleted", username); } else { throw new HubException("Something went wrong."); } } } }
后端配置代码
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1")); } app.UseHttpsRedirection(); app.UseRouting(); app.UseCors(policy => policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:8100")); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapHub<LiveLocationHub>("hubs/livelocation"); endpoints.MapHub<LiveLocationSharersHub>("hubs/locationsharers"); }); }
排查修复要点
协议不匹配问题
- 后端配置了
app.UseHttpsRedirection()强制HTTPS,但前端environment.ts里的hubUrl使用http协议,导致WebSocket握手被重定向失败。 - 修复:将
hubUrl改为https://localhost:5001/hubs/,与API地址协议保持一致。
- 后端配置了
CORS配置缺失WebSocket支持
- 当前CORS配置未允许凭据传递,WebSocket连接可能因权限问题失败。
- 修复:修改CORS配置:
app.UseCors(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().WithOrigins("http://localhost:8100"));
连接状态错误标记
- 前端
createHubConnection方法未等待连接成功就直接标记connectedToHub = true,导致状态与实际连接情况不符。 - 修复:修改组件和服务代码,在连接成功回调中更新状态:
// share-live.service.ts createHubConnection(username: string): Promise<void> { this.hubConnection = new HubConnectionBuilder() .withUrl(this.hubUrl + 'locationsharers',{ skipNegotiation: true, transport: HttpTransportType.WebSockets }) .build(); return this.hubConnection.start() .then(() => this.sendNewSharer(username)) .catch(error => { console.log(error); throw error; }); } // share-live.component.ts private createHubConnection(): void { this.shareLiveService.createHubConnection(this.username) .then(() => this.connectedToHub = true) .catch(() => this.connectedToHub = false); }
- 前端
缺失连接状态监听
- 未监听SignalR连接的关闭、重连事件,无法及时排查连接异常原因。
- 修复:在
share-live.service.ts的createHubConnection中添加状态监听:this.hubConnection.onclose(error => { console.log('连接关闭:', error); }); this.hubConnection.onreconnecting(error => { console.log('正在重连:', error); }); this.hubConnection.onreconnected(connectionId => { console.log('重连成功:', connectionId); });
内容的提问来源于stack exchange,提问作者Seri Ty
相关产品推荐
相关产品推荐

