【发布时间】:2021-03-23 12:00:17
【问题描述】:
我正在尝试通过 Ocelot API 网关在一个简单的微服务中将 Blazor 客户端连接到 SignalR 集线器。我正在为所有 ASP.NET Core 项目使用 SSL。
网关在调用 https 端点时工作正常,当我直接从网关浏览器调用 signalR 集线器端点时,我得到“需要连接 ID”(它正确显示 Ocelot 路由)。
很遗憾,当我尝试从 blazor 客户端应用程序连接到集线器时出现以下错误
失败:Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0] requestId:0HM4U0GLR9ACR:00000001,previousRequestId:没有以前的请求 id,消息:全局错误处理程序中捕获的异常,异常消息:仅支持以 'ws://' 或 'wss://' 开头的 Uris。 (参数“uri”),异常堆栈:在 System.Net.WebSockets.ClientWebSocket.ConnectAsync(Uri uri, CancellationToken cancelToken) 在 Ocelot.WebSockets.Middleware.WebSocketsProxyMiddleware.Proxy(HttpContext 上下文,字符串 serverEndpoint) 在 Ocelot.WebSockets.Middleware.WebSocketsProxyMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext) 在 Ocelot.DownstreamUrlCreator.Middleware.DownstreamUrlCreatorMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext) 在 Ocelot.LoadBalancer.Middleware.LoadBalancingMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext) 在 Ocelot.Request.Middleware.DownstreamRequestInitialiserMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext) 在 Ocelot.Multiplexer.MultiplexingMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext) 在 Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext 上下文) 在 Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
以下是我的代码。
Ocelot API 启动文件
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", policy =>
{
policy.SetIsOriginAllowed(x => true).AllowAnyMethod().AllowAnyHeader();
//policy.SetIsOriginAllowed(x => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
});
});
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseWebSockets();
app.UseOcelot().Wait();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
ocelot.json 配置
{
"Routes": [
{
"DownstreamPathTemplate": "/api/currency/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7004
}
],
"UpstreamPathTemplate": "/api-currency/{everything}",
"UpstreamHttpMethod": [ "Get" ]
},
{
"DownstreamPathTemplate": "/api/currency/{everything}",
"ReRouteIsCaseSensitive": false,
"DownstreamScheme": "wss",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7004
}
],
"UpstreamPathTemplate": "/api-currencyhub/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:7000",
"RequestIdKey": "OcRequestId"
}
}
微服务 API 启动文件
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", policy =>
{
policy.SetIsOriginAllowed(x => true).AllowAnyMethod().AllowAnyHeader();
//policy.SetIsOriginAllowed(x => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
//policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials();
});
});
services.AddSignalR();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<CurrencyHub>("/api/currency/maincurrencyhub");
endpoints.MapControllers();
});
}
}
Blazor 客户端 Razor 页面
@page "/"
@using Microsoft.AspNetCore.SignalR.Client
<h1>Hello, world!</h1>
<h1>Welcome to SignalR with Blazor</h1>
<button class="btn btn-success" @onclick="async () => await ConnectToServer()" disabled="@isConnected">Connect</button>
<button class="btn btn-success" @onclick="async () => await OnGateway()">Gateway</button>
<h3>Connection Status: @connectionStatus</h3>
<div class="row">
<div class="col-4">
@foreach (var item in notifications)
{
<div class="row">
<h4>@item</h4>
</div>
}
</div>
</div>
@code {
//string gatewayUrl = "wss://localhost:7000/api-currency/maincurrencyhub";
string gatewayUrl = "https://localhost:7000/api-currency/maincurrencyhub";
HubConnection gatewayConnection = null;
bool isConnected = false;
string connectionStatus = "Closed";
List<string> notifications = new List<string>();
private async Task ConnectToServer()
{
gatewayConnection = new HubConnectionBuilder()
//.WithUrl(gatewayUrl)
.WithUrl(gatewayUrl, opt => { opt.SkipNegotiation = true; opt.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets; })
.Build();
try
{
await gatewayConnection.StartAsync();
connectionStatus = "Connected :-)";
gatewayConnection.Closed += async (s) =>
{
isConnected = false;
connectionStatus = "Disconnected";
await gatewayConnection.StartAsync();
isConnected = true;
};
gatewayConnection.On<string>("ReceiveMessage", m =>
{
notifications.Add(m);
StateHasChanged();
});
}
catch (Exception ex)
{
}
}
async Task OnGateway()
{
await gatewayConnection.InvokeAsync("Send", "Na Gode");
}
}
我尝试关注Ocelot not passing websockets to microservice 无济于事。 有人能指引我正确的方向吗?
【问题讨论】:
-
嗨,你能成功吗?我也面临同样的问题...
-
你解决了吗?我正在考虑使用 nginx ... =/
标签: asp.net-core microservices blazor-client-side asp.net-core-signalr ocelot