Angular 和 .NET Core 的 SignalR CORS 问题
SignalR CORS issue with Angular and .NET Core
我知道有很多关于这个主题的问题和答案,但没有一个符合我的具体问题。
我正在使用以下版本
- Angular 10.0.14
- @aspnet/signalr 1.0.27
- ASP.NET 核心 3.1
版本更新:
- 我刚刚用@microsoft/signalr 5.0.11 替换了@aspnet/signalr 1.0.27 -> 同样的问题。
SignalR 连接工作得很好,直到我在 Angular 前端添加 accessTokenFactory。
前端
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${environment.bzApiBaseUrl}/hubs/heartbeat`, {
accessTokenFactory: () => token
})
.build();
this.hubConnection
.start()
.then(() => {
console.log('SignalR: Heartbeat - connection started');
this.hubConnection.on('beat', () => {
console.log('SignalR: Heartbeat - Heartbeat received');
});
})
.catch(err => console.log('SignalR: Heartbeat - error while starting connection: ' + err));
});
当我从 HubConnectionBuilder
中删除 accessTokenFactory
时连接建立。
后端
services.AddCors(options =>
{
options.AddPolicy(
name: MyAllowSpecificOrigins,
builder =>
{
builder
.WithOrigins(CorsSettings.TargetDomain)
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials();
});
});
CorsSetting 域的值为 http://localhost:4200
,其中前端为 运行。
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(e =>
{
e.MapControllers();
e.MapHub<HeartbeatHub>("/api/hubs/heartbeat");
});
添加 accessTokenFactory
后在浏览器控制台中记录以下错误:
WebSocketTransport.js:70
WebSocket connection to 'ws://localhost:33258/api/hubs/heartbeat?id=BpBytwkEatklNR-XqGtabA&access_token=eyJ0eXAiOiJKV1QiLCJhbGci... failed:
Utils.js:190
Error: Failed to start the transport 'WebSockets': undefined
dashboard:1
Access to resource at 'http://localhost:33258/api/hubs/heartbeat?id=iWuMeeOKkWCUa8X9z7jXyA&access_token=eyJ0eXAiOiJKV1QiLCJhbGci...' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
我不明白 CORS 问题,因为它似乎是通过使用 accessTokenFactory 向查询字符串添加令牌引发的。
我试过了:
- 将后端 URL 添加到 CORS 来源(根据文档不需要)
- app.UseSignalR 而不是 app.UseEndpoints
- 禁用app.UseHttpsRedirection()
- 以不同方式更改了注册中间件的顺序
- .SetIsOriginAllowed((host) => true) 在 .AllowCredentials()
之后
更新
将 HttpTransportType
设置为 LongPolling
时建立连接。它不适用于 WebSockets
或 ServerSentEvents
。
app.UseEndpoints(e =>
{
e.MapControllers();
e.MapHub<HeartbeatHub>("/api/hubs/heartbeat", options =>
{
options.Transports = HttpTransportType.LongPolling;
});
});
使用长轮询时,令牌似乎作为 HTTP header 而不是查询字符串参数发送。令牌很长,所以我突破了最大值。使用 WebSockets 或 ServerSentEvents 时允许 URL 长度。但我仍然不知道为什么这会导致 CORS 异常。
浏览器不支持 headers websockets,因此必须添加不记名令牌作为查询字符串参数。由于不记名令牌的长度,我们达到了 URL 的最大长度。我们可以缩短我们的令牌或使用参考令牌,另请参阅:https://github.com/aspnet/SignalR/issues/1266
希望这对其他人也有帮助。
我知道有很多关于这个主题的问题和答案,但没有一个符合我的具体问题。
我正在使用以下版本
- Angular 10.0.14
- @aspnet/signalr 1.0.27
- ASP.NET 核心 3.1
版本更新:
- 我刚刚用@microsoft/signalr 5.0.11 替换了@aspnet/signalr 1.0.27 -> 同样的问题。
SignalR 连接工作得很好,直到我在 Angular 前端添加 accessTokenFactory。
前端
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${environment.bzApiBaseUrl}/hubs/heartbeat`, {
accessTokenFactory: () => token
})
.build();
this.hubConnection
.start()
.then(() => {
console.log('SignalR: Heartbeat - connection started');
this.hubConnection.on('beat', () => {
console.log('SignalR: Heartbeat - Heartbeat received');
});
})
.catch(err => console.log('SignalR: Heartbeat - error while starting connection: ' + err));
});
当我从 HubConnectionBuilder
中删除 accessTokenFactory
时连接建立。
后端
services.AddCors(options =>
{
options.AddPolicy(
name: MyAllowSpecificOrigins,
builder =>
{
builder
.WithOrigins(CorsSettings.TargetDomain)
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials();
});
});
CorsSetting 域的值为 http://localhost:4200
,其中前端为 运行。
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(e =>
{
e.MapControllers();
e.MapHub<HeartbeatHub>("/api/hubs/heartbeat");
});
添加 accessTokenFactory
后在浏览器控制台中记录以下错误:
WebSocketTransport.js:70
WebSocket connection to 'ws://localhost:33258/api/hubs/heartbeat?id=BpBytwkEatklNR-XqGtabA&access_token=eyJ0eXAiOiJKV1QiLCJhbGci... failed:
Utils.js:190
Error: Failed to start the transport 'WebSockets': undefined
dashboard:1
Access to resource at 'http://localhost:33258/api/hubs/heartbeat?id=iWuMeeOKkWCUa8X9z7jXyA&access_token=eyJ0eXAiOiJKV1QiLCJhbGci...' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
我不明白 CORS 问题,因为它似乎是通过使用 accessTokenFactory 向查询字符串添加令牌引发的。
我试过了:
- 将后端 URL 添加到 CORS 来源(根据文档不需要)
- app.UseSignalR 而不是 app.UseEndpoints
- 禁用app.UseHttpsRedirection()
- 以不同方式更改了注册中间件的顺序
- .SetIsOriginAllowed((host) => true) 在 .AllowCredentials() 之后
更新
将 HttpTransportType
设置为 LongPolling
时建立连接。它不适用于 WebSockets
或 ServerSentEvents
。
app.UseEndpoints(e =>
{
e.MapControllers();
e.MapHub<HeartbeatHub>("/api/hubs/heartbeat", options =>
{
options.Transports = HttpTransportType.LongPolling;
});
});
使用长轮询时,令牌似乎作为 HTTP header 而不是查询字符串参数发送。令牌很长,所以我突破了最大值。使用 WebSockets 或 ServerSentEvents 时允许 URL 长度。但我仍然不知道为什么这会导致 CORS 异常。
浏览器不支持 headers websockets,因此必须添加不记名令牌作为查询字符串参数。由于不记名令牌的长度,我们达到了 URL 的最大长度。我们可以缩短我们的令牌或使用参考令牌,另请参阅:https://github.com/aspnet/SignalR/issues/1266
希望这对其他人也有帮助。