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 提到的客户端。但我不认为这是正确的解决方案,感觉更像是一个黑客???。
您需要做的是在服务器端添加
这是我的 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
18init() {
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
14public class SignalRConnectionInfo {
public SignalRConnectionInfo();
[JsonProperty("url")]
public string Url {
get;
set;
}
[JsonProperty("accessToken")]
public string AccessToken {
get;
set;
}
}因此,将代码更改为
accessTokenFactory: () => con.accessToken 后,一切正常。
n