让 Ocelot 与 asp.net core “共存”

让 Ocelot 与 asp.net core “共存”,第1张

概述我们的 API 之前是一个单体应用,各个模块的服务是通过 Assembly 集成在一起,最后部署在一个 web server 下的。

我们已经在拆分服务并且在 [Ocelot](https:// 让 Ocelot 与 asp.net core “共存”Intro

我们的 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 “共存”所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1214947.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存