我们的 API 之前是一个单体应用,各个模块的服务是通过 Assembly 集成在一起,最后部署在一个 web server 下的。@H_502_5@
我们已经在拆分服务并且在 Ocelot 的基础上封装了我们自己的网关,但是服务还没有完全拆分,于是有这么一个需求,对于 Ocelot 配置的路由去交给 Ocelot 去转发到真正的服务地址,而那些 Ocelot 没有定义的路由则让交给 AspNetCore
去处理。@H_502_5@实现原理
实现原理是让 Ocelot 作为一个动态分支路由,只有当 Ocelot 配置了对应路由的下游地址才走 Ocelot 的分支,才把请求交给 Ocelot 处理。@H_502_5@
我们可以使用 MapWhen
来处理,接下来就需要知道怎么样判断 Ocelot
是否配置了某一个路由,Ocelot 内部的处理管道,在向下游请求之前是要找到对应匹配的下游路由,所以我们去看一看 Ocelot 的源码,看看 Ocelot 内部是怎么找下游路由的,Ocelot 找下游路由中间件源码@H_502_5@
public async Task Invoke(DownstreamContext context) { var upstreamUrlPath = context.httpContext.Request.Path.ToString(); var upstreamqueryString = context.httpContext.Request.queryString.ToString(); var upstreamHost = context.httpContext.Request.headers["Host"]; Logger.LogDeBUG($"Upstream url path is {upstreamUrlPath}"); var provIDer = _factory.Get(context.Configuration); // 获取下游路由 var downstreamRoute = provIDer.Get(upstreamUrlPath,upstreamqueryString,context.httpContext.Request.Method,context.Configuration,upstreamHost); if (downstreamRoute.IsError) { Logger.LogWarning($"{MIDdlewarename} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}"); SetPipelineError(context,downstreamRoute.Errors); return; } var downstreamPathTemplates = string.Join(",",downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value)); Logger.LogDeBUG($"downstream templates are {downstreamPathTemplates}"); context.TemplatePlaceholdernameAndValues = downstreamRoute.Data.TemplatePlaceholdernameAndValues; await _multiplexer.Multiplex(context,downstreamRoute.Data.ReRoute,_next); }
通过上面的源码,我们就可以判断 Ocelot 是否有与请求相匹配的下游路由信息@H_502_5@实现
既然找到了 Ocelot 如何找下游路由,就先给 Ocelot 加一个扩展吧,实现代码如下,Ocelot 扩展完整代码@H_502_5@
public static IApplicationBuilder USEOcelotWhenRouteMatch(this IApplicationBuilder app,Action<IOcelotPipelineBuilder,OcelotPipelineConfiguration> builderAction) => USEOcelotWhenRouteMatch(app,builderAction,new OcelotPipelineConfiguration()); public static IApplicationBuilder USEOcelotWhenRouteMatch(this IApplicationBuilder app,Action<OcelotPipelineConfiguration> pipelineConfigurationAction,OcelotPipelineConfiguration> builderAction) { var pipelineConfiguration = new OcelotPipelineConfiguration(); pipelineConfigurationAction?.Invoke(pipelineConfiguration); return USEOcelotWhenRouteMatch(app,pipelineConfiguration); } public static IApplicationBuilder USEOcelotWhenRouteMatch(this IApplicationBuilder app,OcelotPipelineConfiguration> builderAction,OcelotPipelineConfiguration configuration) { app.MapWhen(context => { // 获取 OcelotConfiguration var internalConfigurationResponse = context.RequestServices.GetrequiredService<IInternalConfigurationRepository>().Get(); if (internalConfigurationResponse.IsError || internalConfigurationResponse.Data.ReRoutes.Count == 0) { // 如果没有配置路由信息,不符合分支路由的条件,直接退出 return false; } var internalConfiguration = internalConfigurationResponse.Data; var downstreamRouteFinder = context.RequestServices .GetrequiredService<IDownstreamRouteProvIDerFactory>() .Get(internalConfiguration); // 根据请求以及上面获取的Ocelot配置获取下游路由 var response = downstreamRouteFinder.Get(context.Request.Path,context.Request.queryString.ToString(),context.Request.Method,internalConfiguration,context.Request.Host.ToString()); // 如果有匹配路由则满足该分支路由的条件,交给 Ocelot 处理 return !response.IsError && !string.IsNullOrEmpty(response.Data?.ReRoute?.DownstreamReRoute?.FirstOrDefault() ?.DownstreamScheme); },appBuilder => appBuilder.USEOcelot(builderAction,configuration).Wait()); return app; }
使用在 Startup 里@H_502_5@
ConfigurationServices
配置 mvc 和 Ocelot@H_502_5@
Configure
方法里配置 ocelot 和 mvc@H_502_5@
app.USEOcelotWhenRouteMatch((ocelotBuilder,pipelineConfiguration) => { // This is registered to catch any global exceptions that are not handled // It also sets the Request ID if anything is set globally ocelotBuilder.UseExceptionHandlerMIDdleware(); // This is registered first so it can catch any errors and issue an appropriate response ocelotBuilder.UseResponderMIDdleware(); ocelotBuilder.UseDownstreamRouteFinderMIDdleware(); ocelotBuilder.UseDownstreamRequestinitialiser(); ocelotBuilder.UseRequestIDMIDdleware(); ocelotBuilder.UseMIDdleware<ClaimsToheadersMIDdleware>(); ocelotBuilder.UseLoadBalancingMIDdleware(); ocelotBuilder.UseDownstreamUrlCreatorMIDdleware(); ocelotBuilder.USEOutputCacheMIDdleware(); ocelotBuilder.UseMIDdleware<httpRequesterMIDdleware>(); // cors headers ocelotBuilder.UseMIDdleware<CorsMIDdleware>(); });app.UseMvc();
新建一个 TestController@H_502_5@
[Route("/API/[controller]")] public class TestController : ControllerBase { public IActionResult Get() { return Ok(new { Tick = DateTime.UtcNow.Ticks,Msg = "Hello Ocelot",}); } }
具体代码可以参考这个 网关示例项目@H_502_5@
示例项目的 Ocelot 配置是存在 Redis 里面的,配置的 ReRoutes 如下:@H_502_5@
{ "ReRoutes": [ { "DownstreamPathTemplate": "/API.PHP?key=free&appID=0&msg={everything}","UpstreamPathTemplate": "/API/chat/{everything}","UpstreamhttpMethod": [ "Get","POST","PUT","PATCH","DELETE","OPTIONS" ],"AddheadersToRequest": { },"RequestIDKey": "RequestID","ReRouteIsCaseSensitive": false,"Servicename": "","DownstreamScheme": "http","DownstreamHostAndPorts": [ { "Host": "API.qingyunke.com","Port": 80 } ],"DangerousAcceptAnyServerCertificateValIDator": false } ],"GlobalConfiguration": { "httpHandlerOptions": { "AllowautoRedirect": false,"UsecookieContainer": false,"UseTracing": false } }}
运行项目进行测试:@H_502_5@
访问 Ocelot 定义的路由 http://localhost:65125/api/chat/hello ,返回信息如图所示:@H_502_5@
@H_502_5@@H_502_5@
访问 Mvc 定义的路由 http://localhost:65125/api/test,返回信息如图所示:@H_502_5@
@H_502_5@@H_502_5@
上面正常的返回就表示我们的 Ocelot 和 Mvc 同时工作了~@H_502_5@Referencehttps://github.com/ThreeMammals/Ocelothttps://github.com/WeihanLi/AspNetCorePlayground/tree/master/TestGateway 总结
以上是内存溢出为你收集整理的让 Ocelot 与 asp.net core “共存”全部内容,希望文章能够帮你解决让 Ocelot 与 asp.net core “共存”所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)