【问题标题】:WebSocket failed to connectWebSocket 连接失败
【发布时间】:2022-10-17 20:01:55
【问题描述】:

我正在尝试为我的应用程序制作一种实时位置共享功能,但 SignalR 部分存在一些问题。

只是对我在这里尝试做的事情的简短描述:这个中心应该只发送实时分享他们位置的人。首先,我尝试为发件人建立连接,当按下开始按钮时,连接开始,但它一直处于“正在连接”状态,并且将发送其位置的新用户的消息不会注册了,我想知道我做错了什么。我按照教程进行聊天并尝试适应我的需求,但可能需要添加或编辑某些内容才能按我的意愿工作。

分享-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};
  }
}

分享-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));
  }
}

环境.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");
            });
        }

【问题讨论】:

  • 好的:所以您的 Angular 客户端尝试 - 但从未真正“连接” - 到您的 ASP.Net Core 后端。正确的?问:您是否能够对 ASP.Net Core 进行故障排除?您是否看到任何连接请求?问:您使用的是哪个版本的 ASP.Net Core?
  • @paulsm4 是的,它从未真正“连接”过。我尝试在 OnConnectedAsync() 方法中放置一个断点,但它似乎没有到达它并且我没有看到任何连接请求。我正在使用 ASP.Net Core 6
  • @paulsm4 显然问题是 url 在 http 之后缺少 ':',但它仍然不起作用,我收到以下错误:1. WebSocket 连接到 'ws://localhost:5001/hubs/locationsharers'失败:2.[2022-10-08T16:52:57.249Z] 错误:无法启动连接:错误:WebSocket 连接失败。在服务器上找不到连接,端点可能不是 SignalR 端点,服务器上不存在连接 ID,或者存在阻止 WebSocket 的代理。如果您有多个服务器,请检查是否启用了粘性会话。
  • 我赞成你的问题,并冒昧地更改了标题。请看这里(然后发回你的发现):stackoverflow.com/questions/70216272 问:你在哪里/如何在你的 Angular 应用程序中配置了“端点”?
  • @paulsm4 我在问题中添加了环境文件和配置方法。如果您还需要什么,请随时询问

标签: angular typescript signalr signalr.client asp.net-core-signalr


【解决方案1】:

解决了这个问题,其实是一个小问题,只要稍加注意就可以解决。

在 enviroments.ts 文件中,集线器的 url 缺少一个“s”,因此不是“http”而是“https”

export const environment = {
  production: false,
  url:'https://localhost:5001/api',
  hubUrl: 'https://localhost:5001/hubs/',
  mapbox: {
    accessToken: 'token'
  }
};

【讨论】:

    猜你喜欢
    • 2018-12-19
    • 1970-01-01
    • 2016-04-20
    • 2013-12-17
    • 2016-05-13
    • 2015-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多