websocket SignalR:协商工作,但消息未发送(.NET/Angular)

ijnw1ujt  于 2023-08-05  发布在  .NET
关注(0)|答案(2)|浏览(82)

我试图让一个非常基本的SignalR示例工作,它基于Microsoft's tutorial和Visual Studio创建的Weatherforecast .NET/Angular SPA作为基础,因为这是我以后想使用SignalR的同一类型的项目。The entire source code is at GitHub.
看起来好像握手/协商工作了,并且建立了一个WebSocket连接--但是没有消息在那里流动。以下是Chrome开发者工具所显示的内容:x1c 0d1x的数据
我觉得我忽略了一些小东西,但我很难看到它可能是什么。
我首先调整了Program.cs文件,这是相关代码:

builder.Services.AddSignalR(options =>
{
    options.EnableDetailedErrors = true;
});

var app = builder.Build();

...

app.UseCors();
  
//app.MapHub<ProgressHub>("/progressHub");
app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<ProgressHub>("/progresshub"); // Map the hub URL here
});

app.Run();

字符串
请注意,MS建议使用app.MapHub<ProgressHub>("/progressHub");,但某些资源建议使用app.UseEndpoints。看起来没什么区别。另外,我尝试使用app.UseWebSockets();,但也没有改变任何东西。此外,我确保启用CORS。
这是我添加的控制器方法,它应该在SignalR通道上发送消息:

[HttpPost("startProcess")]
public async Task<IActionResult> StartProcess()
{
    // Some logic to start the long-running process
    for (int i = 0; i < 10; i++)
    {
        await Task.Delay(1000);

        // Report progress to the client
        await _hubContext.Clients.All.SendAsync("ReceiveProgressUpdate", $"Step {i + 1} completed.");
    }

    return Ok("[]");
}


单步执行代码时,不会引发任何异常,代码运行时不会出现任何问题。在Angular客户端,我安装了signalr包并创建了一个服务:

export class SignalRService {
  private hubConnection: HubConnection;
  private progressSubject: Subject<string> = new Subject<string>();

  constructor() {
    this.hubConnection = new HubConnectionBuilder()
      .withUrl('https://localhost:44429/progresshub')
      .build();

    this.hubConnection.on('ReceiveProgressUpdate', (progressMessage: string) => {
      this.progressSubject.next(progressMessage);
    });

    this.hubConnection.start().catch(err => console.error(err));
  }

  getProgressUpdates() {
    return this.progressSubject.asObservable();
  }
}


现在我在SignalR组件中使用该服务,但progressUpdates数组仍然为空:

export class SignalRComponent implements OnInit {
  progressUpdates: string[] = [];
  _httpClient: HttpClient;

  constructor(private httpClient: HttpClient, private signalRService: SignalRService) {
    this._httpClient = httpClient;
  }

  ngOnInit() {
    this.signalRService.getProgressUpdates().subscribe((progressMessage: string) => {
      this.progressUpdates.push(progressMessage);
    });
  }

  startProcess() {
    this.httpClient.post('https://localhost:44429/weatherforecast/startProcess', {}).subscribe();
  }
}


此外,我已经在Windows中打开了WebSocket协议,因为这也是SO上的建议:

3wabscal

3wabscal1#

我下载了你的repo并修改了proxy.conf.js文件,如下所示。而且效果很好。您可以根据需要更改其他设置。
我还启用了客户端日志记录,以便我们可以建立连接。

测试结果

x1c 0d1x的数据

proxy.conf.js

const { env } = require('process');

const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
  env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:50822';


const PROXY_CONFIG = [
  {
    context: [
      "/weatherforecast",
      "/progresshub"
   ],
    target: target, 
    changeOrigin: true,  
    logLevel: "debug",
    rejectUnauthorzied: true, 
    secure: false,            
    strictSSL: true,          
    withCredentials: true,
    ws: true
  }
]

module.exports = PROXY_CONFIG;

字符串

signal-r.service.ts

import { Injectable } from '@angular/core';
import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
import * as signalR from '@microsoft/signalr';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SignalRService {
  private hubConnection: HubConnection;
  private progressSubject: Subject<string> = new Subject<string>();

  constructor() {
    this.hubConnection = new signalR.HubConnectionBuilder()
      .withUrl('https://localhost:44429/progresshub', signalR.HttpTransportType.WebSockets | signalR.HttpTransportType.LongPolling).configureLogging(signalR.LogLevel.Debug)
      .build();

    this.hubConnection.on('ReceiveProgressUpdate', (progressMessage: string) => {
      this.progressSubject.next(progressMessage);
    });
    this.hubConnection.start().catch(err => console.error(err));
  }

  getProgressUpdates() {
    return this.progressSubject.asObservable();
  }
}

ebdffaop

ebdffaop2#

我终于找到了罪魁祸首,它是ASP代理,默认配置不允许WebSocket连接。proxy.conf.js中的PROXY_CONFIG const需要这样设置:

const PROXY_CONFIG = [
  {
    context: ["/progresshub"], 
    target: target,
    secure: false,
    ws: true // Enable WebSocket proxying
  },
  {
    context: [
      "/weatherforecast",
   ],
    target: target,
    secure: false,
    headers: {
      Connection: 'Keep-Alive'
    }
  }
]

字符串
需要将配置拆分为weatherforecast(或任何其他)API和WebSocket的单独上下文,因为Websocket连接不允许Keep-Alive头。
这是this post on reddit的功劳。

相关问题