如何自定义书写中间件?

如何,自定义,书写,中间件 · 浏览次数 : 228

小编点评

**什么是中间件?** 中间件是一种软件组件,在应用程序的处理流程中扮演着重要角色。它与请求和响应之间 middle,处理请求并将其传递给下一个中间件或最终处理结果。 **为什么要使用中间件?** 使用中间件可以执行一系列预处理或最终处理操作,例如身份验证、日志记录或错误处理。通过使用中间件,可以将请求和响应封装起来,提高应用程序的可重用性。 **定义中间件** 中间件的处理流程就像一个俄罗斯套娃,它包含两个主要部分:请求处理器和响应处理器。请求处理器接收请求,并将其传递给下一个中间件处理。响应处理器接收来自下一个中间件的响应,并将其传递给应用程序。 **配置使用中间件** 在应用程序启动之前,可以使用 `IApplicationBuilder` 接口的 `UseMiddleware` 方法注册中间件。中间件会被配置到应用程序的管道中,并处理请求。 **演示** ```csharp // Configure middleware public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); // 开发环境使用 app.UseSwagger(); app.UseSwaggerUI(option => { foreach (string version in typeof(ApiVersions).GetEnumNames()) { option.SwaggerEndpoint($"\/swagger/{version}/swagger.json\", $"版本:{version}"); } }); } // 使用中间件 app.UseMyMiddlewareOne(); // 使用授权 app.UseAuthorization(); // 使用路由 app.UseRouting(); } ``` **总结** 中间件是一种软件组件,用于处理应用程序请求并将其传递给下一个中间件或最终处理结果。通过使用中间件,可以实现代码可重用性、性能和安全性。

正文

一、什么是中间件?

中间件是一种装配到应用管道以处理请求和响应的软件。是介于request与response处理过程之间的一个插件(一道处理过程),相对比较轻量级,并且在全局上会影响到request对象和response对象的属性。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。每个组件:

1、选择是否将请求传递到管道中的下一个组件。

2、可在管道中的下一个组件前后执行工作。

原理图:

多个中间件时,中间件请求和响应的中间件顺序相反

图片

二、为什么使用中间件?

在我们很多时候,当一个请求过来之后,我们想对这个请求做各种各样的操作和记录,这个时候我们可以加入中间件。目的就是对这个请求和响应做处理,其实不难理解,这就是类似于工业机器,一个商品出来之前会有很多关卡,会执行N到工序。最后加工出来的产品就是我们想要的,也是安全的。这些关卡就类似于中间件的作用了。

微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件。核心就是一系列的请求委托,Run、Use、Map

  • Run:是最后一道工序,管道末尾。

  • Use:连接请求委托,next 向下走。

  • Map:扩展用作约定创建管道分支。

三、定义中间件:

中间件的处理流程就像一个俄罗斯套娃,微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件,这也是套娃模式的由来。RequestDelegate是管道的核心。ApplicationBuilder就是接收了很多个RequestDelegae把它拼到一起。

定义:

/// <summary>
    /// 中间件定义和业务逻辑
    /// </summary>
    public class MyMiddleware
    {
        private readonly RequestDelegate _next;

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="next"></param>
        public MyMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        /// <summary>
        /// 方法名必须命名为 Invoke或者 InvokeAsync,才能有效执行下一个中间件
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext httpContext)
        {
            /*
             * 在这里可以书写业务处理逻辑
             *中间件的处理流程就像一个俄罗斯套娃,微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。
             * 通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件(这也是套娃模式的由来)。
             */
            try
            {
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                //内部出现异常
                httpContext.Response.StatusCode = 500;
            }
            finally
            {
                var statusCode = httpContext.Response.StatusCode;
                var msg = "";
                switch (statusCode)
                {
                    case 401:
                        msg = "未授权";
                        break;
                    case 403:
                        msg = "拒绝访问";
                        break;
                    case 404:
                        msg = "未找到服务";
                        break;
                    case 405:
                        msg = "405 Method Not Allowed";
                        break;
                    case 500:
                        msg = "服务器内部错误";
                        break;
                    case 502:
                        msg = "请求错误";
                        break;
                }
                if (!string.IsNullOrWhiteSpace(msg))
                {
                    await HandleExceptionAsync(httpContext, msg);
                }
            }
        }

        /// <summary>
        /// 处理Http响应异常
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        private async Task HandleExceptionAsync(HttpContext httpContext, string msg)
        {
            ErrorModel error = new ErrorModel
            {
                code = httpContext.Response.StatusCode,
                msg = msg
            };
            var result = JsonConvert.SerializeObject(error);
            httpContext.Response.ContentType = "application/json;charset=utf-8";
            await httpContext.Response.WriteAsync(result).ConfigureAwait(false);
        }
    }

封装拓展方法:

创建一个中间件拓展类,为每个自定义中间件创建方法,通过IApplicationBuilder拓展方法暴露

/// <summary>
    /// 中间件拓展类
    /// </summary>
    public static  class MyMiddlewareExtensions
    {
        /// <summary>
        /// 将封装的中间件委托到一个类中,通过IApplicationBuilder拓展方法暴露
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseMyMiddlewareOne(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<MyMiddleware>();
        }

        /*
         * 下面还可以拓展其他自定义中间件方法,通过IApplicationBuilder暴露
         */
    }

四、配置使用中间件:

使用中间件:

注意:使用中间件,顺序非常重要。比如此处,要放在权限处理的前面。不然请求从管道回来的时候,会先走消息处理,然后再判断权限,这样的话就无法处理了。因为使用多个中间件时,中间件请求和响应的顺序是相反的,此处还是爬楼看上面的原理图比较清晰。

 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

                //开发环境使用
                app.UseSwagger();
                app.UseSwaggerUI(option =>
                {
                    foreach (string version in typeof(ApiVersions).GetEnumNames())
                    {
                        option.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"版本:{version}");
                    }
                });
            }

            app.UseRouting();

            //使用自定义中间件:
            app.UseMyMiddlewareOne();//注册自定义中间件

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

五、演示:

定义测试Http接口:

    /// <summary>
        /// 自定义中间件测试
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        [HttpGet]
        public int  MiddleWareTest(string param)
        {
            /*
             * note:此处的字符串是否是数字不做判断,当输入的非数字字符串时,强转Int服务内部会
             */
            int Number = int.Parse(param);
            return Number;

        }

Http请求测试:

图片

与如何自定义书写中间件?相似的内容:

如何自定义书写中间件?

## 一、什么是中间件? 中间件是一种装配到应用管道以处理请求和响应的软件。是介于request与response处理过程之间的一个插件(一道处理过程),相对比较轻量级,并且在全局上会影响到request对象和response对象的属性。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。每个组

4.10 x64dbg 反汇编功能的封装

LyScript 插件提供的反汇编系列函数虽然能够实现基本的反汇编功能,但在实际使用中,可能会遇到一些更为复杂的需求,此时就需要根据自身需要进行二次开发,以实现更加高级的功能。本章将继续深入探索反汇编功能,并将介绍如何实现反汇编代码的检索、获取上下一条代码等功能。这些功能对于分析和调试代码都非常有用,因此是书中重要的内容之一。在本章的学习过程中,读者不仅可以掌握反汇编的基础知识和技巧,还能够了解如

基础知识小结

为什么会存在这个 大概在2021年中左右,我决定未来5-8年还是在搞技术,所以我就在想我该如何完善自己的知识体系,要怎么样才能成为一个合格的、专业的前端工程师,如果后面不止于前端,我要怎么样才能在这个行业走的更远。所以就有了先提升基础的知识点的想法,虽然专业是软件工程,但是这些基础真的基本都还给书本

操作系统开发:编写开机引导

操作系统是用来管理与协调硬件工作的,开发一款操作系统有利于理解底层的运转逻辑,本篇内容主要用来理解操作系统是如何启动的,又是如何加载磁盘中的内核的,该系列文章参考各类底层书籍,通过自己的理解并加以叙述,让内容变得更加简单,一目了然,即可学到知识又能提高自己的表述能力。 注释: 该系列笔记是在学习《操

DotNetGuide新增C#/.NET/.NET Core充电站(让你学习不迷路)

DotNetGuide简介 记录、收集和总结C#/.NET/.NET Core基础知识、学习路线、开发实战、学习视频、文章、书籍、项目框架、社区组织、开发必备工具、常见面试题、面试须知、简历模板、以及自己在学习和工作中的一些微薄见解。希望能和大家一起学习,共同进步👊【让现在的自己不再迷茫✨,如果本

DotNetGuide专栏C#/.NET/.NET Core充电站(让你学习不迷路)

DotNetGuide简介 记录、收集和总结C#/.NET/.NET Core基础知识、学习路线、开发实战、编程技巧练习、学习视频、文章、书籍、项目框架、社区组织、开发必备工具、常见面试题、面试须知、简历模板、以及自己在学习和工作中的一些微薄见解。希望能和大家一起学习,共同进步。如果本知识库能为您提

MoneyPrinterPlus:AI自动短视频生成工具,详细使用教程

MoneyPrinterPlus是一款使用AI大模型技术,一键批量生成各类短视频,自动批量混剪短视频,自动把视频发布到抖音,快手,小红书,视频号上的轻松赚钱工具。 之前有出过一期基本的介绍,但是后台收到有些小伙伴说,不知道如何使用。 今天我将会手把手的详细介绍如何使用MoneyPrinterPlus

读书笔记丨远程服务调用和RESTful,如何分析和抉择?

摘要:相信未来REST规范将会变得更加流行和普及。 本文分享自华为云社区《云原生时代,远程服务调用和RESTful,如何分析和抉择?》,作者:breakDawn 。 随着云原生的概念越来越火,服务的架构应该如何发展和演进,成为很多程序员关心的话题。大名鼎鼎的《深入理解java虚拟机》一书作者于21年

[转帖]计算机为什么选用补码表示整数?

https://zhuanlan.zhihu.com/p/501536618 深入理解计算机系统(原书第3版) 京东 ¥91.80 去购买​ 整数主要有三种表示方法:原码、反码、补码,目前的计算机都采用补码表示方法。各种表示方法的定义如下: 原码 第一位表示符号,剩余位表示数值 反码 正数的反码是其

我为什么选择Wiki.js记笔记?

很长一段时间里,我都被困扰着,感觉陷入了笔记的泥潭,而积累的如此多的笔记也没有形成我自己的知识体系。 之前的记笔记方式 笔记的来源 微信公众号 技术博客 纸质书籍 官网文档 PDF 自己的零散想法 网页 之前的笔记软件 有好几个: 为知笔记 浏览器书签 MarkDown 文档 Calibre 电子书