Ошибка 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, и это сработало. Я считаю, что при запуске выбрал неправильные настройки.

9 ответов

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

Я столкнулся с более тонкой проблемой и исправил ее, добавив

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

Я указывал не на ту конечную точку. Я использовал

https://localhost:5001/api/message-hub вместо

https://localhost:5001/message-hub (дополнительный / api)

Кроме того, если вы используете Angular, вы, вероятно, получите ошибку Websocket not OPEN сразу после исправления этой ошибки, поэтому вот ссылка, которая избавит вас от дополнительных поисков.

У меня была та же проблема, и оказалось, что launchSettings.json в той части, где он говорит signalRchatServer, ничего не делает, URL, который работал со мной, был URL-адресом iisexpress, я говорю это, потому что есть много мест, где говорят, URL-адрес находится ниже.

В моем случае в этом не было необходимости, мне не хватало https вместо http, и это работало как шарм.

const connection = new signalR.HubConnectionBuilder()
  .configureLogging(signalR.LogLevel.Debug)
  .withUrl('https://localhost:44308/message')
  .build();

Я трачу на это почти два дня и наконец понял,

Когда возникает эта ошибка?

  • Когда вы обновляете существующий проект сервера SignalR до.Net Core, но не обновляете клиент
  • Когда вы создаете сервер SignalR с использованием ядра.Net, но используете традиционную среду.Net для клиента

Почему возникает эта ошибка?

  • Ошибка возникает из-за того, что новый SignalR не позволяет использовать старый сервер и новый клиент или новый сервер и старый клиент.

  • Это означает, что если вы создаете сервер SignalR с использованием ядра.Net, тогда вы должны создать клиент с использованием.Net Core.

Это было проблемой в моем случае.

Я столкнулся с той же проблемой в моем приложении Angular при попытке подключиться к службе Azure SignalR в службе Azure.

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

И ниже был мой код функции init() в службе Angular.

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 все работало как обычно.

Можете ли вы проверить настройки прокси-сервера, установить вкладку подключения к интернет-опциям Настройки Lan -> Выбрать, автоматически определять настройки и снять отметку с настройки прокси.

У меня была такая же ошибка из-за перекрестного происхождения. Это решило это для меня program.cs (dotnet 6) или startup.cs (dotnetcore < 6)

      app.UseCors(builder => builder
            .AllowAnyHeader()
            .AllowAnyMethod()
            .SetIsOriginAllowed(_ => true)
            .AllowCredentials()
        );

Обратите внимание, что вам не следует открывать все источники, если это не среда разработки или особые случаи.

Другие вопросы по тегам