在Ocelot中使用自定义的中间件(二)

在上文中《在Ocelot中使用自定义的中间件(一)》,我介绍了如何在Ocelot中使用自定义的中间件来修改下游服务的response body。今天,我们再扩展一下设计,让我们自己设计的中间件变得更为通用,使其能够应用在不同的Route上。比如,我们可以设计一个通用的替换response body的中间件,然后将其应用在多个Route上。

Ocelot的配置文件

我们可以将Ocelot的配置信息写在appsettings.json中,当然也可以将其放在单独的json文件里,然后通过ConfigureAppConfiguration的调用,将单独的json文件添加到配置系统中。无论如何,基于JSON文件的Ocelot配置都是可以加入我们自定义的内容的,基于数据库的或者其它存储的配置文件信息或许扩展起来并不方便,因此,使用JSON文件作为配置源还是一个不错的选择。比如,我们可以在ReRoute的某个配置中添加以下内容:


{

  "DownstreamPathTemplate": "/api/themes",

  "DownstreamScheme": "http",

  "DownstreamHostAndPorts": [

    {

      "Host": "localhost",

      "Port": 5010

    }

  ],

  "UpstreamPathTemplate": "/themes-api/themes",

  "UpstreamHttpMethod": [ "Get" ],

  "CustomMiddlewares": [

    {

      "Name": "themeCssMinUrlReplacer",

      "Enabled": true,

      "Config": {

        "replacementTemplate": "/themes-api/theme-css/{name}"

      }

    }

  ]

}

然后就需要有一个方法能够解析这部分配置内容。为了方便处理,可以增加以下配置Model,专门存放CustomMiddlewares下的配置信息:


public class CustomMiddlewareConfiguration

{

    public string DownstreamPathTemplate { get; set; }

    public string UpstreamPathTemplate { get; set; }

    public int ReRouteConfigurationIndex { get; set; }

    public string Name { get; set; }

    public bool Enabled { get; set; }

    public Dictionary<string, object> Config { get; set; }

}

然后定义下面的扩展方法,用以从IConfiguration对象中解析出所有的CustomMiddleware的配置信息:


public static IEnumerable<CustomMiddlewareConfiguration> GetCustomMiddlewareConfigurations(this IConfiguration config)

{

    var reRoutesConfigSection = config.GetSection("ReRoutes");

    if (reRoutesConfigSection.Exists())

    {

        var reRoutesConfigList = reRoutesConfigSection.GetChildren();

        for (var idx = 0; idx < reRoutesConfigList.Count(); idx++)

        {

            var reRouteConfigSection = reRoutesConfigList.ElementAt(idx);

            var upstreamPathTemplate = reRouteConfigSection.GetSection("UpstreamPathTemplate").Value;

            var downstreamPathTemplate = reRouteConfigSection.GetSection("DownstreamPathTemplate").Value;

            var customMidwareConfigSection = reRouteConfigSection.GetSection("CustomMiddlewares");

            if (customMidwareConfigSection.Exists())

            {

                var customMidwareConfigList = customMidwareConfigSection.GetChildren();

                foreach (var customMidwareConfig in customMidwareConfigList)

                {

                    var customMiddlewareConfiguration = customMidwareConfig.Get<CustomMiddlewareConfiguration>();

                    customMiddlewareConfiguration.UpstreamPathTemplate = upstreamPathTemplate;

                    customMiddlewareConfiguration.DownstreamPathTemplate = downstreamPathTemplate;

                    customMiddlewareConfiguration.ReRouteConfigurationIndex = idx;

                    yield return customMiddlewareConfiguration;

                }

            }

        }

    }

 

    yield break;

}

CustomMiddleware基类

为了提高程序员的开发体验,我们引入CustomMiddleware基类,在Invoke方法中,CustomMiddleware对象会读取所有的CustomMiddleware配置信息,并找到属于当前ReRoute的CustomMiddleware配置信息,从而决定当前的CustomMiddleware是否应该被执行。相关代码如下:


public abstract class CustomMiddleware : OcelotMiddleware

{

    #region Private Fields

 

    private readonly ICustomMiddlewareConfigurationManager customMiddlewareConfigurationManager;

    private readonly OcelotRequestDelegate next;

 

    #endregion Private Fields

 

    #region Protected Constructors

 

    protected CustomMiddleware(OcelotRequestDelegate next,

        ICustomMiddlewareConfigurationManager customMiddlewareConfigurationManager,

        IOcelotLogger logger) : base(logger)

    {

        this.next = next;

        this.customMiddlewareConfigurationManager = customMiddlewareConfigurationManager;

    }

 

    #endregion Protected Constructors

 

    #region Public Methods

 

    public async Task Invoke(DownstreamContext context)

    {

        var customMiddlewareConfigurations = from cmc in this

                                                .customMiddlewareConfigurationManager

                                                .GetCustomMiddlewareConfigurations()

                                             where cmc.DownstreamPathTemplate == context

                                                    .DownstreamReRoute

                                                    .DownstreamPathTemplate

                                                    .Value &&

                                                   cmc.UpstreamPathTemplate == context

                                                    .DownstreamReRoute

                                                    .UpstreamPathTemplate

                                                    .OriginalValue

                                             select cmc;

 

        var thisMiddlewareName = this.GetType().GetCustomAttribute<CustomMiddlewareAttribute>(false)?.Name;

        var customMiddlewareConfiguration = customMiddlewareConfigurations.FirstOrDefault(x => x.Name == thisMiddlewareName);

        if (customMiddlewareConfiguration?.Enabled ?? false)

        {

            await this.DoInvoke(context, customMiddlewareConfiguration);

        }

 

        await this.next(context);

    }

 

    #endregion Public Methods

 

    #region Protected Methods

 

    protected abstract Task DoInvoke(DownstreamContext context, CustomMiddlewareConfiguration configuration);

 

    #endregion Protected Methods

}

接下来就简单了,只需要让自定义的Ocelot中间件继承于CustomMiddleware基类就行了,当然,为了解耦类型名称与中间件名称,使用一个自定义的CustomMiddlewareAttribute:


[CustomMiddleware("themeCssMinUrlReplacer")]

public class ThemeCssMinUrlReplacer : CustomMiddleware

{

    private readonly Regex regex = new Regex(@"\w+://[a-zA-Z0-9]+(\:\d+)?/themes/(?<theme_name>[a-zA-Z0-9_]+)/bootstrap.min.css");

    public ThemeCssMinUrlReplacer(OcelotRequestDelegate next,

        ICustomMiddlewareConfigurationManager customMiddlewareConfigurationManager,

        IOcelotLoggerFactory loggerFactory)

        : base(next, customMiddlewareConfigurationManager, loggerFactory.CreateLogger<ThemeCssMinUrlReplacer>())

    {

    }

 

    protected override async Task DoInvoke(DownstreamContext context, CustomMiddlewareConfiguration configuration)

    {

        var downstreamResponseString = await context.DownstreamResponse.Content.ReadAsStringAsync();

        var downstreamResponseJson = JObject.Parse(downstreamResponseString);

        var themesArray = (JArray)downstreamResponseJson["themes"];

        foreach(var token in themesArray)

        {

            var cssMinToken = token["cssMin"];

            var cssMinValue = cssMinToken.Value<string>();

            if (regex.IsMatch(cssMinValue))

            {

                var themeName = regex.Match(cssMinValue).Groups["theme_name"].Value;

                var replacementTemplate = configuration.Config["replacementTemplate"].ToString();

                var replacement = $"{context.HttpContext.Request.Scheme}://{context.HttpContext.Request.Host}{replacementTemplate}"

                    .Replace("{name}", themeName);

                cssMinToken.Replace(replacement);

            }

        }

 

        context.DownstreamResponse = new DownstreamResponse(

            new StringContent(downstreamResponseJson.ToString(Formatting.None), Encoding.UTF8, "application/json"),

            context.DownstreamResponse.StatusCode, context.DownstreamResponse.Headers, context.DownstreamResponse.ReasonPhrase);

    }

}

自定义中间件的注册

在上文介绍的BuildCustomOcelotPipeline扩展方法中,加入以下几行,就完成所有自定义中间件的注册:


var customMiddlewareTypes = from type in typeof(Startup).Assembly.GetTypes()

                            where type.BaseType == typeof(CustomMiddleware) &&

                                  type.IsDefined(typeof(CustomMiddlewareAttribute), false)

                            select type;

foreach (var customMiddlewareType in customMiddlewareTypes)

{

    builder.UseMiddleware(customMiddlewareType);

}

当然,app.UseOcelot的调用要调整为:

1

app.UseOcelot((b, c) => b.BuildCustomOcelotPipeline(c).Build()).Wait();

运行

重新运行API网关,得到结果跟之前的一样。所不同的是,我们可以将ThemeCssMinUrlReplacer在其它的ReRoute配置上重用了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习理论引导 电子版_机器学习理论篇1:机器学习的数学基础(2)

本节主要就是讲述的机器学习的数学基础&#xff0c;提到数学基础&#xff0c;可能一眼就会是满眼的枯燥、没意思&#xff0c;但是成就英雄的路上注定了孤独&#xff0c;要想要真正的在学术上有所突破就必须挨得住寂寞&#xff0c;受得住孤独&#xff0c;才能真正的走进熟悉直到…

洛谷T172100 商店-贪心

解题思路&#xff1a; 贪心 代码如下&#xff1a; #include <iostream> #include <algorithm> using namespace std; const int N 100010; int a[N], w[N]; int ans;int main() {int n, m;cin >> n >> m;for (int i 1; i < n; i)cin >> a…

vue动态切换css文件_vue实现样式之间的切换及vue动态样式的实现方法

编程之家收集整理的这篇文章主要介绍了vue实现样式之间的切换及vue动态样式的实现方法&#xff0c;编程之家小编觉得挺不错的&#xff0c;现在分享给大家&#xff0c;也给大家做个参考。前言既然我们选择了vue&#xff0c;那么在做东西时就不要想着去操作dom&#xff0c;所有的…

[蓝桥杯2015决赛]机器人数目-枚举

题目描述 少年宫新近邮购了小机器人配件&#xff0c;共有3类&#xff0c;其中&#xff0c; A类含有&#xff1a;8个轮子&#xff0c;1个传感器 B类含有: 6个轮子&#xff0c;3个传感器 C类含有&#xff1a;4个轮子&#xff0c;4个传感器 他们一共订购了100套机器人&#xff0c;…

终结“永恒之蓝”后,再战“永恒之黑”

引子&#xff1a;2003年的“抗击非典”&#xff0c;17年后的2020年“抗击新冠”。2017年的“永恒之蓝”&#xff0c;3年后的2020年“永恒之黑”。历史&#xff1a;2017年5月13日&#xff0c;在“胖哥技术堂”中发布了《截杀“WannaCrypt”&#xff0c;终结“永恒之蓝”》。三年…

python 广告拦截_Python如何在抓取时欺骗反广告块过滤器?

Javascript解析您遇到的问题是在页面加载后加载数据的JavaScript过滤器。警告您正在使用adblock的消息以原始HTML格式存在&#xff0c;并且是完全静态的。当JavaScript调用能够验证adblock存在或不存在的位置时&#xff0c;它将被替换。有几种方法可以解决这个问题&#xff0c;…

使用.Net Core编写命令行工具(CLI)

使用.Net Core编写命令行工具(CLI)命令行工具(CLI)命令行工具(CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面&#xff0c;它通常不支持鼠标&#xff0c;用户通过键盘输入指令&#xff0c;计算机接收到指令后&#xff0c;予以执行。通常认为&#xff0c;命令行工具(C…

[蓝桥杯2015决赛]奇怪的数列-双指针+模拟

题目描述 从X星截获一份电码&#xff0c;是一些数字&#xff0c;如下&#xff1a; 13 1113 3113 132113 1113122113 … YY博士经彻夜研究&#xff0c;发现了规律&#xff1a; 第一行的数字随便是什么&#xff0c;以后每一行都是对上一行“读出来” 比如第2行&#xff0c;是对第…

与php有区别_php://output和php://stdout的区别

php中文网最新课程每日17点准时技术干货分享PHP包含了以php://开头的一系列输出输出流&#xff0c;如php://stdin, php://stdout等。今天查看代码时&#xff0c;忽然想到一个问题&#xff1a;php://output和php://stdout有什么区别&#xff1f;从PHP的官方文献中找答案&#xf…

浅谈 Kubernetes Scheduling-Framework 插件的实现

最近几个月一直在研究 kubernetes 的 scheduling-framework 调度框架&#xff0c;发现还是十分有意思的&#xff0c;我自己也实现了一个基于 scheduling-framework 调度框架的自定义调度器&#xff0c;希望感兴趣的同学一起学习&#xff1a;https://github.com/NJUPT-ISL/Yoda-…

C++实现线段树(lazy-tag方法)-区间修改,区间查询

代码如下&#xff1a; #include <iostream> using namespace std; const int N 10010; typedef long long LL; LL input[N];struct node {int l, r;LL sum;LL add; } tree[4 * N];void build(int l, int r, int u) {tree[u].l l;tree[u].r r;if (l r) {tree[u].sum …

.NET Core开发实战(第25课:路由与终结点:如何规划好你的Web API)--学习笔记(上)...

25 | 路由与终结点&#xff1a;如何规划好你的Web API路由系统在 ASP.NET MVC 框架里面就已经存在了&#xff0c;在 ASP.NET Core 框架里面进行了改进路由系统的核心作用是指 URL 和 应用程序 Controller 的对应关系的一种映射这个映射关系实际上有两种作用&#xff1a;1、把 U…

catia如何整列加工_CATIA V5 R20加工模块的自动编程方法

在数控加工领域&#xff0c;运用CATIAV5R20自动编程方法一方面可以方便地实现零件的数控编程&#xff0c;生成高效、高精度的NC程序&#xff1b;另一方面&#xff0c;可以通过实体仿真刀具路径&#xff0c;检验是否有明显的过切或者干涉现象&#xff0c;及时作出相应的修改&…

Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)

好吧&#xff0c;这个题目我也想了很久&#xff0c;不知道如何用最简单的几个字来概括这篇文章&#xff0c;原本打算取名《Angular单页面应用基于Ocelot API网关与IdentityServer4ASP.NET Identity实现身份认证与授权》&#xff0c;然而如你所见&#xff0c;这样的名字实在是太…

slot属性值_深入理解vue中的slot与slot

作者/云荒杯倾写在前面vue中关于插槽的文档说明很短&#xff0c;语言又写的很凝练&#xff0c;再加上其和methods&#xff0c;data&#xff0c;computed等常用选项使用频率、使用先后上的差别&#xff0c;这就有可能造成初次接触插槽的开发者容易产生“算了吧&#xff0c;回头再…

[蓝桥杯][2013年第四届真题]幸运数-模拟+dfs

题目描述 幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成 。 首先从1开始写出自然数1,2,3,4,5,6,… 1 就是第一个幸运数。 我们从2这个数开始。把所有序号能被2整除的项删除&#xff0c;变为&#xff1a; 1 _ 3 _ 5 _ 7 _ 9 … 把它们缩紧&#xff0c;重…

【翻译】.NET 5 Preview 1 发布

.NET 5 Preview 1 发布去年年底,我们发布了.NET Core 3.0和3.1.这些版本添加了桌面应用程序模型Windows Forms(WinForms)和WPF,ASP.NET Blazor用于构建SPA应用程序和用于构建分布式应用和服务的gRPC模板、用于与gRPC对话丰富的客户端代码生成、REST API服务等等.我们很高兴看到…

cubemx lan8720模块_通过STM32cubeMX将STM32F767+LAN8720+LwIP+FreeRTOS的以太网实现

本文使用了正点原子的阿波罗开发板&#xff0c;接下来我将粗略的对STM32F767通过STM32cubeMX进行以太网协议配置。具体步骤1.首先使能ETH&#xff0c;模式选择RMII&#xff1b;2.使能LWIP和FREERTOS&#xff1b;因为阿波罗的开发板PHY芯片的ETH_DXT1和ETH_DXT0用的是PG13&#…

[蓝桥杯][历届试题]网络寻路-dfs,图的遍历

题目描述 X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包&#xff0c;为了安全起见&#xff0c;必须恰好被转发两次到达目的地。该包可能在任意一个节点产生&#xff0c;我们需要知道该网络中一共有多少种不同的转发路径。 源地址和目标地址…

Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(二)

上文已经介绍了Identity Service的实现过程。今天我们继续&#xff0c;实现一个简单的Weather API和一个基于Ocelot的API网关。回顾《Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权&#xff08;一&#xff09;》Weather APIWeather API实现非常简单&#xf…