Intro

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

我们已经在拆分服务并且在 Ocelot 的基础上封装了我们自己的网关,但是服务还没有完全拆分,于是有这么一个需求,对于 Ocelot 配置的路由去交给 Ocelot 去转发到真正的服务地址,而那些 Ocelot 没有定义的路由则让交给 AspNetCore 去处理。

实现原理

实现原理是让 Ocelot 作为一个动态分支路由,只有当 Ocelot 配置了对应路由的下游地址才走 Ocelot 的分支,才把请求交给 Ocelot 处理。

我们可以使用 MapWhen 来处理,接下来就需要知道怎么样判断 Ocelot 是否配置了某一个路由,Ocelot 内部的处理管道,在向下游请求之前是要找到对应匹配的下游路由,所以我们去看一看 Ocelot 的源码,看看 Ocelot 内部是怎么找下游路由的,Ocelot 找下游路由中间件源码

  1. public async Task Invoke(DownstreamContext context)

  2. {

  3. var upstreamUrlPath = context.HttpContext.Request.Path.ToString();

  4. var upstreamQueryString = context.HttpContext.Request.QueryString.ToString();

  5. var upstreamHost = context.HttpContext.Request.Headers["Host"];

  6. Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");

  7. var provider = _factory.Get(context.Configuration);

  8. // 获取下游路由

  9. var downstreamRoute = provider.Get(upstreamUrlPath, upstreamQueryString, context.HttpContext.Request.Method, context.Configuration, upstreamHost);

  10. if (downstreamRoute.IsError)

  11. {

  12. Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");

  13. SetPipelineError(context, downstreamRoute.Errors);

  14. return;

  15. }

  16. var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));

  17. Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");

  18. context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;

  19. await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);

  20. }

通过上面的源码,我们就可以判断 Ocelot 是否有与请求相匹配的下游路由信息

实现

既然找到了 Ocelot 如何找下游路由,就先给 Ocelot 加一个扩展吧,实现代码如下,Ocelot 扩展完整代码

  1. public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app,

  2. Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction)

  3. => UseOcelotWhenRouteMatch(app, builderAction, new OcelotPipelineConfiguration());

  4. public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app,

  5. Action<OcelotPipelineConfiguration> pipelineConfigurationAction,

  6. Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction)

  7. {

  8. var pipelineConfiguration = new OcelotPipelineConfiguration();

  9. pipelineConfigurationAction?.Invoke(pipelineConfiguration);

  10. return UseOcelotWhenRouteMatch(app, builderAction, pipelineConfiguration);

  11. }

  12. public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app, Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction, OcelotPipelineConfiguration configuration)

  13. {

  14. app.MapWhen(context =>

  15. {

  16. // 获取 OcelotConfiguration

  17. var internalConfigurationResponse =

  18. context.RequestServices.GetRequiredService<IInternalConfigurationRepository>().Get();

  19. if (internalConfigurationResponse.IsError || internalConfigurationResponse.Data.ReRoutes.Count == 0)

  20. {

  21. // 如果没有配置路由信息,不符合分支路由的条件,直接退出

  22. return false;

  23. }

  24. var internalConfiguration = internalConfigurationResponse.Data;

  25. var downstreamRouteFinder = context.RequestServices

  26. .GetRequiredService<IDownstreamRouteProviderFactory>()

  27. .Get(internalConfiguration);

  28. // 根据请求以及上面获取的Ocelot配置获取下游路由

  29. var response = downstreamRouteFinder.Get(context.Request.Path, context.Request.QueryString.ToString(),

  30. context.Request.Method, internalConfiguration, context.Request.Host.ToString());

  31. // 如果有匹配路由则满足该分支路由的条件,交给 Ocelot 处理

  32. return !response.IsError

  33. && !string.IsNullOrEmpty(response.Data?.ReRoute?.DownstreamReRoute?.FirstOrDefault()

  34. ?.DownstreamScheme);

  35. }, appBuilder => appBuilder.UseOcelot(builderAction, configuration).Wait());

  36. return app;

  37. }

使用

在 Startup 里

ConfigurationServices 配置 mvc 和 Ocelot

Configure 方法里配置 ocelot 和 mvc

  1. app.UseOcelotWhenRouteMatch((ocelotBuilder, pipelineConfiguration) =>

  2. {

  3. // This is registered to catch any global exceptions that are not handled

  4. // It also sets the Request Id if anything is set globally

  5. ocelotBuilder.UseExceptionHandlerMiddleware();

  6. // This is registered first so it can catch any errors and issue an appropriate response

  7. ocelotBuilder.UseResponderMiddleware();

  8. ocelotBuilder.UseDownstreamRouteFinderMiddleware();

  9. ocelotBuilder.UseDownstreamRequestInitialiser();

  10. ocelotBuilder.UseRequestIdMiddleware();

  11. ocelotBuilder.UseMiddleware<ClaimsToHeadersMiddleware>();

  12. ocelotBuilder.UseLoadBalancingMiddleware();

  13. ocelotBuilder.UseDownstreamUrlCreatorMiddleware();

  14. ocelotBuilder.UseOutputCacheMiddleware();

  15. ocelotBuilder.UseMiddleware<HttpRequesterMiddleware>();

  16. // cors headers

  17. ocelotBuilder.UseMiddleware<CorsMiddleware>();

  18. });

  19. app.UseMvc();

新建一个 TestController

  1. [Route("/api/[controller]")]

  2. public class TestController : ControllerBase

  3. {

  4. public IActionResult Get()

  5. {

  6. return Ok(new

  7. {

  8. Tick = DateTime.UtcNow.Ticks,

  9. Msg = "Hello Ocelot",

  10. });

  11. }

  12. }

具体代码可以参考这个 网关示例项目

示例项目的 Ocelot 配置是存在 Redis 里面的,配置的 ReRoutes 如下:

  1. {

  2. "ReRoutes": [

  3. {

  4. "DownstreamPathTemplate": "/api.php?key=free&appid=0&msg={everything}",

  5. "UpstreamPathTemplate": "/api/chat/{everything}",

  6. "UpstreamHttpMethod": [

  7. "Get",

  8. "POST",

  9. "PUT",

  10. "PATCH",

  11. "DELETE",

  12. "OPTIONS"

  13. ],

  14. "AddHeadersToRequest": {

  15. },

  16. "RequestIdKey": "RequestId",

  17. "ReRouteIsCaseSensitive": false,

  18. "ServiceName": "",

  19. "DownstreamScheme": "http",

  20. "DownstreamHostAndPorts": [

  21. {

  22. "Host": "api.qingyunke.com",

  23. "Port": 80

  24. }

  25. ],

  26. "DangerousAcceptAnyServerCertificateValidator": false

  27. }

  28. ],

  29. "GlobalConfiguration": {

  30. "HttpHandlerOptions": {

  31. "AllowAutoRedirect": false,

  32. "UseCookieContainer": false,

  33. "UseTracing": false

  34. }

  35. }

  36. }

运行项目进行测试:

访问 Ocelot 定义的路由 http://localhost:65125/api/chat/hello ,返回信息如图所示:

访问 Mvc 定义的路由 http://localhost:65125/api/test,返回信息如图所示:

上面正常的返回就表示我们的 Ocelot 和 Mvc 同时工作了~

Reference

  • https://github.com/ThreeMammals/Ocelot

  • https://github.com/WeihanLi/AspNetCorePlayground/tree/master/TestGateway

让 Ocelot 与 asp.net core “共存”相关推荐

  1. ASP.NET Core on K8s学习之旅(13)Ocelot API网关接入

    [云原生]| 作者/Edison Zhou 这是恰童鞋骚年的第232篇原创文章 上一篇介绍了Ingress的基本概念和Nginx Ingress的基本配置和使用,考虑到很多团队都在使用Ocelot作为 ...

  2. Asp.Net Core Ocelot Consul 微服务

    做一个简单的微服务架构如下图: 这个图表示的是一个网关代理Consul的两个服务,consul每个服务注册集群 安装 Consul的服务,这里安装单机版的,集群版配置最低要求(3个Consul ser ...

  3. ASP.NET Core中Ocelot的使用:基于服务发现的负载均衡

    本系列相关文章: <ASP.NET Core中Ocelot的使用:API网关的应用> <ASP.NET Core中Ocelot的使用:基于Spring Clound Netflix ...

  4. 使用ASP.NET Core、Ocelot、MongoDB和JWT的微服务

    目录 介绍 开发环境 技术 体系结构 源代码 微服务 API网关 客户端应用 单元测试 使用健康检查进行监视 如何运行应用程序 如何部署应用程序 进一步阅读 本文显示了一个使用ASP.NET Core ...

  5. Asp.Net Core微服务再体验

    Asp.Net Core微服务再体验 原文:Asp.Net Core微服务再体验 ASP.Net Core的基本配置 .在VS中调试的时候有很多修改Web应用运行端口的方法.但是在开发.调试微服务应用 ...

  6. ASP.NET Core Web 应用程序开发期间部署到IIS自定义主机域名并附加到进程调试

    想必大家之前在进行ASP.NET Web 应用程序开发期间都有用到过将我们的网站部署到IIS自定义主机域名并附加到进程进行调试. 那我们的ASP.NET Core Web 应用程序又是如何部署到我们的 ...

  7. Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

     1622219047536 写在前面   Api网关我们之前是用 .netcore写的 Ocelot的,使用后并没有完全达到我们的预期,花了些时间了解后觉得kong可能是个更合适的选择. 简单说下 ...

  8. ASP.NET Core整合Zipkin链路跟踪

    前言 在日常使用ASP.NET Core的开发或学习中,如果有需要使用链路跟踪系统,大多数情况下会优先选择SkyAPM.我们之前也说过SkyAPM设计确实比较优秀,巧妙的利用DiagnosticSou ...

  9. 可能是Asp.net Core On host、 docker、kubernetes(K8s) 配置读取的最佳实践

     写在前面 为了不违反广告法,我竭尽全力,不过"最佳实践"确是标题党无疑,如果硬要说的话 只能是个人最佳实践. 问题引出 可能很多新手都会遇到同样的问题:我要我的Asp.net ...

最新文章

  1. Datawhale来浙大啦!
  2. 最简单的SAP云平台开发教程 - 如何开发UI5应用并运行在SAP云平台上
  3. 华为:对部分顶尖学生实行年薪制 最高200万元
  4. python变量类型-Python变量类型
  5. 【django】聚合函数和排序函数
  6. met40如何升级成鸿蒙系统,再见了,EMUI11!你好,华为鸿蒙!
  7. 向量表示 运动抛物线_初学讲义之高中物理(四)常见运动类型
  8. 将python算法转为scala_将Python转换为scalaasp
  9. 新中大银色快车数据恢复
  10. DNF最新纯图色脚本框架2022-4-27
  11. 微信小程序自定义导航栏
  12. python十以内加减法_【小学】 生成10以内的加减法
  13. 1553B通信项目开发笔记(四)bu61580程序编写,实现回环之RT端
  14. cursor的所有样式
  15. 强化学习入门 Q-learning与SARSA
  16. Electron学习笔记 4 添加系统功能
  17. mp9486电源经典应用电路
  18. 程序验证(四):一阶理论
  19. BIOS知识枝桠——Event
  20. Three.js 多细节层次

热门文章

  1. 迁移聊天记录到Teams
  2. 中输入learn_Scikit-learn新版本发布,一行代码秒升级
  3. 【python】-- Django 中间件、缓存、信号
  4. Framework Design Studio 发布了
  5. Python中文编码判别及转换
  6. 充分利用系统的组策略 保障共享目录安全
  7. 《Objective-C基础教程》第二章 对C的扩展
  8. 如何在宝塔面板启用 ASP.NET CORE 网站并自动申请 HTTPS 证书
  9. RowVersion字段从SqlServer到PostgreSQL的迁移
  10. ASP.NET Core启动地址配置方法及优先级顺序