对我的服务器使用 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 聊天教程
这是我的创业
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 中重新创建了信号器实现并且它起作用了。我相信我在启动时选择了错误的设置。
connection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug) // add this for diagnostic clues
.withUrl("http://localhost:5000/decisionHub", {
skipNegotiation: true, // skipNegotiation as we specify WebSockets
transport: signalR.HttpTransportType.WebSockets // force WebSocket transport
})
.build();
我遇到了更棘手的问题,我通过添加来修复它
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
在客户端,正如 @Caims 提到的。但我不认为这是正确的解决方案,感觉更像是一个 hack 😊。 你要做的就是在服务器端添加
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 错误,因此这里一个链接可以帮助您避免更多搜索。
当我尝试连接到 Azure SignalR 服务 Azure Function 时,我在 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
后,一切正常。
我为此浪费了将近两天的时间,终于弄清楚了,
什么时候出现这个错误?
为什么会出现这个错误?
发生错误是因为新的SignalR不允许您使用旧服务器和新客户端或新服务器和旧客户端
这意味着如果您使用.Net Core创建SignalR服务器,那么您必须使用.Net Core创建客户端
这就是我的案例中的问题。
就我而言,不需要所有这些东西,我错过了 https 而不是 http,它就像一个魅力。
const connection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug)
.withUrl('https://localhost:44308/message')
.build();
由于跨源,我遇到了同样的错误。这为我解决了program.cs (dotnet 6) 或startup.cs (dotnetcore < 6)
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(_ => true)
.AllowCredentials()
);
注意,如果不是开发环境或特殊情况,不要打开所有源。