我想通过 signalR 将我的 maui blazor 应用程序(Windows)连接到 .net blazor 服务器应用程序,以便我可以将消息从服务器推送到客户端。我也用wpf dekstop app测试了,结果是一样的,握手失败。
我正在使用的版本:Microsoft.AspNetCore.SignalR.Client" Version="6.0.1",我尝试了 7.0.1。
有趣的是,@localhost 一切正常。并且 blazor wasm 的 signalR 在同一台服务器上功能齐全。
服务器端托管于@akamai
错误信息详情:
Microsoft.AspNetCore.SignalR.Client.HubConnection: Trace: Waiting on Connection Lock in StartAsyncInner (/_/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs:247).
Microsoft.AspNetCore.SignalR.Client.HubConnection: Trace: The HubConnection is attempting to transition from the Disconnected state to the Connecting state.
Microsoft.AspNetCore.SignalR.Client.HubConnection: Debug: Starting HubConnection.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Starting HttpConnection.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Establishing connection with server at 'https://staging.vetat.work/hub/printertool'.
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler: Trace: Sending HTTP request POST 'https://staging.asd/hub/printertool/negotiate?negotiateVersion=1'.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Established connection 'B07mkUpGtdoEwG6C9uQZbA' with the server.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Starting transport 'WebSockets' with Url: https://staging.vetat.work/hub/printertool.
Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport: Information: Starting transport. Transfer mode: Text. Url: 'wss://staging.vetat.work/hub/printertool?id=UGcgq9uJEOL5hZkA1iZxCQ'.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Error: Failed to start connection. Error starting transport 'WebSockets'.
System.Net.WebSockets.WebSocketException (0x80004005): The server returned status code '200' when status code '101' was expected.
at System.Net.WebSockets.WebSocketHandle.ValidateResponse(HttpResponseMessage response, String secValue, ClientWebSocketOptions options)
at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken, ClientWebSocketOptions options)
at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.DefaultWebSocketFactory(WebSocketConnectionContext context, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartTransport(Uri connectUrl, HttpTransportType transportType, TransferFormat transferFormat, CancellationToken cancellationToken)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Skipping transport WebSockets because it failed to initialize.
System.Net.WebSockets.WebSocketException (0x80004005): The server returned status code '200' when status code '101' was expected.
at System.Net.WebSockets.WebSocketHandle.ValidateResponse(HttpResponseMessage response, String secValue, ClientWebSocketOptions options)
at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken, ClientWebSocketOptions options)
at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.DefaultWebSocketFactory(WebSocketConnectionContext context, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartTransport(Uri connectUrl, HttpTransportType transportType, TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.SelectAndStartTransport(TransferFormat transferFormat, CancellationToken cancellationToken)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Establishing connection with server at 'https://staging.asd/hub/printertool'.
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler: Trace: Sending HTTP request POST 'https://staging.asd/hub/printertool/negotiate?negotiateVersion=1'.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Established connection 'trPpDN3vsUzTTUqSu0LdwQ' with the server.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Starting transport 'ServerSentEvents' with Url: https://staging.asd/hub/printertool.
Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport: Information: Starting transport. Transfer mode: Text.
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler: Trace: Sending HTTP request GET 'https://staging.asd/hub/printertool?id=snz3w-l4JZ8sYDtO8cK9jQ'.
我尝试了 maui 应用程序,我也尝试了调试、日志记录、wpf 应用程序。我希望我可以从服务器向客户端发送消息。
var url = _configuration[MauiConstants.AppConfig.SignalR];
_connection = new HubConnectionBuilder()
.WithUrl(url, options =>
{
options.AccessTokenProvider = () => Task.FromResult(token);
})
.ConfigureLogging(logging =>
{
// Log to the Console
logging.AddDebug();
// This will set ALL logging to Debug level
logging.SetMinimumLevel(LogLevel.Trace);
})
.WithAutomaticReconnect()
.Build();
为了授权,我使用不记名令牌
这是服务器配置:
if (config.SignalR.AllowCors)
{
_ = app.UseCors(builder =>
{
_ = builder.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins(config.SignalR.CorsAddress)
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
}
_ = authenticationBuilder.AddJwtBearer(AuthConstant.Scheme.PrinterTool, options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.Audience = $"{Audience.PrinterTool:G}";
var signingKey = Convert.FromBase64String(secretKey);
options.TokenValidationParameters = new TokenValidationParameters
{
AuthenticationType = AuthConstant.Scheme.PrinterTool,
ValidateIssuer = false,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(signingKey),
ClockSkew = TimeSpan.FromMinutes(Convert.ToDouble(config.AdminAppAuthentication.ExpiresIn))
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers["Token-Expired"] = "true";
}
return Task.CompletedTask;
},
OnMessageReceived = context =>
{
//If the request is for our hub
var path = context.HttpContext.Request.Path;
if (path.StartsWithSegments(config.SignalR.PrinterToolMainHubRoute))
{
var authorization = context.Request.Headers?.Authorization.FirstOrDefault(a => a.StartsWith("Bearer "));
if (!string.IsNullOrEmpty(authorization))
{
context.Token = authorization.Substring("Bearer ".Length);
}
}
return Task.CompletedTask;
}
};
});
我想这个问题已经解决了。 我遇到了同样的问题,我解决了更改产品服务器上的 nginx 配置
更改此:
proxy_set_header Connection keep-alive;
通过这个:
proxy_set_header Connection $http_connection;
完成nginx配置:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name api.your-domain.com;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
ssl_certificate /etc/nginx/ssl/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/your-domain.com/privkey.pem;
location / {
proxy_pass http://172.17.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_headers_hash_max_size 512;
proxy_headers_hash_bucket_size 128;
}
}