Angular / SignalR错误:无法完成与服务器的协商

时间:2018-08-29 21:14:44

标签: asp.net angular signalr

在服务器上使用SignalR,在客户端上使用Angular ...运行客户端时,出现以下错误:

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 Chat Tutorial

这是我的创业公司

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

这是我的客户:

    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中重新创建了signalr实施,并且它起作用了。我相信我在启动时选择了错误的设置。

7 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

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

[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()函数代码。

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

public class SignalRConnectionInfo {
    public SignalRConnectionInfo();

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

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

答案 2 :(得分:0)

我遇到了更苗条的问题,并通过添加

解决了该问题
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets

在客户端,如@Caims所述。但是我认为这不是正确的解决方案,更像是骇客。 您要做的是在服务器端添加AllowCredentials。无论如何,当谈到Azure时,您都无法继续进行该修复。因此,无需仅在客户端启用WSS。

这是我的 ConfigureServices 方法:

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

这是我的 配置 方法:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

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

    app.UseMvc();
}

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

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

答案 3 :(得分:0)

我为此花了将近两天时间,终于想通了,

何时发生此错误?

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

为什么会发生此错误?

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

  • 这意味着如果您使用.Net Core创建SignalR服务器,则必须使用.Net Core创建客户端

这是我的问题。

答案 4 :(得分:0)

我遇到了同样的问题,结果表明其中的signalRchatServer不执行任何操作的launchSettings.json,与我一起使用的网址是iisexpress的网址,我之所以这么说是因为它们在很多地方说网址是下面的网址。

enter image description here

答案 5 :(得分:0)

在我的情况下,并不需要所有这些东西,我错过了https而不是http,它像一个魅力一样起作用。

A
---
A

答案 6 :(得分:0)

我指向了错误的端点。我正在使用

https://localhost:5001/api/message-hub 而不是

https://localhost:5001/message-hub(额外的/api)

此外,如果您使用的是 Angular,您可能会在修复此错误后立即收到 Websocket not OPEN 错误,因此 here's 一个链接可以让您免于进行更多搜索。