换个角度理解设计模式之中间件思想-2-伪中间件

系列文章的目录:https://blog.csdn.net/hjkl950217/article/details/89490709


记住:设计模式重理解,轻照搬

上期遗留的坑

上期的那种写法使用时还有“只适用基础数据结构不变、使用多变、无序、无分支的场景”的问题,这次想解决的就是多变、无序的场景

项目背景

每次写文章我都会在文章开始前描述下背景,为的是让读者知道背景后,可以更好的在自己的项目中应用,所以这期一样要废话一下。

我们项目需要重构登陆验证部分,将之前的登陆代码简化,在不影响功能的前提下优化代码流程。这些功能包括:

  1. 一些基础请求头检查
  2. 检查IP地址
  3. 检查登陆者在session中是否存在
  4. 需要URL白名单
  5. 验证完成后将用户的数据加载到一个地方,供业务代码使用
  6. 内部测试用户为了测试方便会使用固定token

分析

分析下这个业务的特点有:

  1. 验证情况可能有多种,但目的都是为了登陆.(分支少线性逻辑
  2. 需要在验证流程中添加一些检查
  3. 不同用户需要一些特别的检查逻辑
  4. 整体上可以分为 验证前验证中验证后

结合.net core中的中间件写法+Context思想(一次业务,将相关的基础数据放在一个实体中,可参考HttpConetxt),我搞出了一种类中间件的业务代码。

伪中间件实现

1. 设计Context

我按照整体流程的3个阶段将Context设计为这样:
在这里插入图片描述

  1. 需要的配置和数据:包括从请求中采集的信息和我们的一些配置
  2. 分析是否返回给前端: 存放每步执行后的处理结果,如果结果为true了则直接返回。(比如IP检查没过,就没必要进行后续检查了)
  3. 向IOC写数据:这里利用IOCScoped模式,临时保存用户的信息

说白了就是把要处理的所有信息提前安放好,而不是用到了 才去找

2. 设计业务中间件

中间件代码最重要的就是需要知道它的下一个是谁。
比如中间件定义:

    public interface IAuthenticationMw
    {
        IAuthenticationMw Next { get; set; }
        int ExecuteOrder { get; }
        Task InvokeAsync(IAuthenticationContext context);
    }

那么实现代码中一定会有:

        public Task InvokeAsync(IAuthenticationContext context)
        {
            return this.Next(context);
        }

这样就起来了。

而我们的业务中,检查有一个不过则直接返回,这就要求顺序了(比如检查没通过时,一定不能调用加载数据的方法)

3. 设计检查服务

前面说的都是中间件的接口,我们还需要一种类用来将它们管理起来。我设计了一个CheckService,它负责将所有中间件从IOC中取出来,并为它们的Next属性复制。此时就用到了ExecuteOrder属性。

       //初始化
        public CheckService(IEnumerable<IAuthenticationMw> authenticationMws)
        {
            this.firstMw = this.SortMw(authenticationMws);
        }
       
       //真实调用
        public async Task<IAuthenticationContext> StartCheckAsync(IAuthenticationContext context)
        {
            await this.firstMw.InvokeAsync(context);
            IAuthenticationContext result = this.ProcessResult(context);
            return result;
        }

挂接代码:

        protected IAuthenticationMw SortMw(IEnumerable<IAuthenticationMw> authenticationMws)
        {
            var mwLsit = authenticationMws
              .OrderBy(i => i.ExecuteOrder)
              .ToArray();

            //排序
            //为保证最后一个中间件的next不会执行,所以这里使用降序
            IAuthenticationMw tempMw = mwLsit.FirstOrDefault();
            foreach (var item in mwLsit)
            {
                tempMw.Next = item;
                tempMw = item;
            }
            tempMw.Next = mwLsit.LastOrDefault();
            return mwLsit.FirstOrDefault();
        }

剩余的事就是将需求拆分,并且实现IAuthenticationMw接口即可。在认证的地方只要调用到CheckServiceStartCheckAsync方法即可完成检查了。

后续增加只需要增加新的中间件代码即可,修改也只会影响单个中间件自己,是不是非常棒?

调用

我是使用的IOC去配置初始化的代码,利用它的延迟加载特性,可以在调用到用户数据时才会触发这些检查逻辑,因为每个项目使用的IOC框架可能不一样,我就没有再贴代码了,大体思路是:

  1. Context的构造方法中写需要的数据,由IOC负责注入
  2. 将所有中间件注册到IOC中,这样CheckService就能一次拿到所有中间件代码
  3. CheckService的构造方法中写需要中间件集合+排列顺序
  4. IOC中配置用户数据的创建方法,在需要用户数据时即可触发CheckService的调用

总结

好处:非常适合做一些业务检查,扩展性维护性非常好
缺点:要额外编写一些代码,不懂这个套路的人阅读代码会有点困难

到第2个阶段,我们已经能解决"基础数据结构不变,但业务情况多变、无序”的情况。登陆认证业务中,一般需要的基础数据非常少,所以很适合这种方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值