关于asp.net:Angular/SignalR 错误:无法完成与服务器的协商

Angular/SignalR Error: Failed to complete negotiation with the server

为我的服务器使用 SignalR,为我的客户端使用 Angular...当我运行我的客户端时,我收到以下错误:

1
2
3
4
5
zone.js:2969 OPTIONS https://localhost:27967/chat/negotiate 0 ()

Utils.js:148 Error: Failed to complete negotiation with the server: Error

Utils.js:148 Error: Failed to start the connection: Error

我猜这与 CORS 有关...我正在尝试实现一个简单的聊天应用程序。我正在使用 SignalR 的最新版本:

这里是包含我正在关注的教程代码的 github。
SignalR 聊天教程

这是我的启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace signalrChat
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
            {
                builder
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .WithOrigins("http://localhost:4200");
            }));

            services.AddSignalR();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("CorsPolicy");

            app.UseSignalR(routes =>
            {
                routes.MapHub<ChatHub>("/chat");
            });
        }
    }
}

这是我的客户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    import { Component, OnInit } from '@angular/core';
import { HubConnection, HubConnectionBuilder } from '@aspnet/signalr';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  private hubConnection: HubConnection;

  nick = '';
  message = '';
  messages: string[] = [];

  ngOnInit() {
    this.nick = window.prompt('Your name:', 'John');

    this.hubConnection = new HubConnectionBuilder().withUrl('https://localhost:27967/chat').build();

    this.hubConnection
    .start()
    .then(() => console.log("Connection Started!"))
    .catch(err => console.log("Error while establishing a connection :("));

    this.hubConnection.on('sendToAll', (nick: string, receiveMessage: string) => {
      const text = `${nick}: ${receiveMessage}`;
      this.messages.push(text);
    })
  }

  public sendMessage(): void {
    this.hubConnection
    .invoke('sendToAll', this.nick, this.message)
    .catch(err => console.log(err));
  }

}

我想这可能是与cors有关的东西。谢谢!

编辑:我刚刚在 Visual Studio 中重新创建了信号器实现,它工作正常。我相信我在启动时选择了错误的设置。


1
2
3
4
5
6
7
connection = new signalR.HubConnectionBuilder()
    .configureLogging(signalR.LogLevel.Debug)
    .withUrl("http://localhost:5000/decisionHub", {
      skipNegotiation: true,
      transport: signalR.HttpTransportType.WebSockets
    })
    .build();


我遇到了更棘手的问题,我通过添加

来解决它

1
2
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets

@Caims 提到的客户端。但我不认为这是正确的解决方案,感觉更像是一个黑客???。
您需要做的是在服务器端添加 AllowCredentials 。无论如何,当它来到 Azure 时,您无法继续进行该修复。所以不需要只在客户端启用 WSS。

这是我的 ConfigureServices 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(o => o.AddPolicy("CorsPolicy", builder => {
        builder
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials()
        .WithOrigins("http://localhost:4200");
    }));

    services.AddSignalR();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

这是我的配置方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseCors("CorsPolicy");
    app.UseSignalR(routes =>
    {
        routes.MapHub<NotifyHub>("/notify");
    });

    app.UseMvc();
}

最后这就是我从客户端连接的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const connection = new signalR.HubConnectionBuilder()
      .configureLogging(signalR.LogLevel.Debug)
      .withUrl("http://localhost:5000/notify", {
        //skipNegotiation: true,
        //transport: signalR.HttpTransportType.WebSockets
      }).build();

connection.start().then(function () {
    console.log('Connected!');
}).catch(function (err) {
    return console.error(err.toString());
});

connection.on("BroadcastMessage", (type: string, payload: string) => {
    this.msgs.push({ severity: type, summary: payload });
});


n


n


n


我为此浪费了将近两天的时间,终于想通了,

什么时候出现这个错误?

  • 当您将现有 SignalR 服务器项目升级到 .Net Core
    但不要升级客户端
  • 创建 SignalR 服务器时
    使用 .Net 核心,但您使用传统的 .Net 框架作为客户端

为什么会出现这个错误?

  • 发生错误是因为新的 SignalR 不允许您使用旧服务器


    当我尝试连接到 Azure SignalR 服务 Azure Function 时,我在 Angular 应用程序中遇到了同样的问题。

    1
    2
    3
    4
    5
    6
    7
    [FunctionName("Negotiate")]
    public static IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Anonymous,"get","post", Route = null)] HttpRequest req, [SignalRConnectionInfo(HubName ="broadcast")] SignalRConnectionInfo info,
        ILogger log) {
        log.LogInformation("Negotiate trigger function processed a request.");
        return info != null ? (ActionResult) new OkObjectResult(info) : new NotFoundObjectResult("SignalR could not load");
    }

    下面是我在 Angular 服务中的 init() 函数代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    init() {
        this.getSignalRConnection().subscribe((con: any) => {
            const options = {
                accessTokenFactory: () => con.accessKey
            };

            this.hubConnection = new SignalR.HubConnectionBuilder()
                .withUrl(con.url, options)
                .configureLogging(SignalR.LogLevel.Information)
                .build();

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

            this.hubConnection.on('newData', data => {
                this.mxChipData.next(data);
            });
        });
    }

    我的问题在于 con.accessKey。我刚刚检查了 SignalRConnectionInfo 类的属性,了解到我需要使用 accessToken 而不是 accessKey.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class SignalRConnectionInfo {
        public SignalRConnectionInfo();

        [JsonProperty("url")]
        public string Url {
            get;
            set;
        }
        [JsonProperty("accessToken")]
        public string AccessToken {
            get;
            set;
        }
    }

    因此,将代码更改为 accessTokenFactory: () => con.accessToken 后,一切正常。


    n