【对比学习】koa.js、Gin与asp.net core——中间件
2021-04-20 16:26
                         标签:就是   read   host   面向切面   分析   ddl   ONBUILD   nic   apt    编程语言都有所不同,各个语言解决同一类问题而设计的框架,确有共通之处,毕竟是解决同一类问题,面临的挑战大致相同,比如身份验证,api授权等等,鄙人对node.js,golang,.net core有所涉猎,对各自的web框架进行学习的过程中发现了确实有相似之处。下面即对node.js的koa、golang的gin与.net core的asp.net core三种不同的web后端框架的中间件做一个分析对比 静态资源中间件为例:静态资源地址没有路由匹配,盲目引入静态资源,会报404. 洋葱执行:从上到下依次执行,匹配路由响应,再返回至中间件进行执行中间件,【先从外向内,然后再从内向外】 钩子(Hook)函数,中间件函数 与koa中间件执行顺序一致 当在中间件或handler中启动新的goroutine时,不能使用原始的上下文 使用IApplicationBuilder 创建中间件管道 Map 扩展用作约定来创建管道分支。  ");
        });
    }
    //请求会匹配 map1...map2...没匹配到路由的统统会执行app.Run
}
//像golang的gin一样,map也支持嵌套
app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});
public class Startup
{
    private static void HandleMultiSeg(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map multiple segments.");
        });
    }
    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1/seg1", HandleMultiSeg);
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}
//MapWhen 基于给定谓词的结果创建请求管道分支。 Func ");
        });
    }
}
//UseWhen 也是基于给定谓词的结果创建请求管道分支。 与 MapWhen 不同的是,如果这个分支发生短路或包含终端中间件,则会重新加入主管道:
public class Startup
{
    private readonly ILogger 在 对于asp.net core的中间件与koa.js,gin中间件,实现形式略有不同,但是终极目标只有一个,就是AOP,面向切面编程,减少代码量,不至于在某一个路由匹配的方法中去编写同样的代码。在asp.net core之前,还是asp.net的时候,也有类似的AOP实现,去继承各种FilterAttribute ,重写方法,如启用属性路由,创建自定义授权过滤器,创建自定义身份验证过滤器,模型验证过滤器 【对比学习】koa.js、Gin与asp.net core——中间件 标签:就是   read   host   面向切面   分析   ddl   ONBUILD   nic   apt    原文地址:https://www.cnblogs.com/RandyField/p/12258189.htmlweb框架中间件对比
Node-Koa.js
应用级中间件
//如果不写next,就不会向下匹配--匹配任何一个路由
app.use(async(ctx,next)=>{
    console.log(new Date())
    await next();
})路由级中间件
 router.get('/news',async(ctx,next)=>{
     console.log("this is news")
     await next();
 })错误处理中间件
app.use(async(ctx,next)=>{
    //应用级中间件 都需要执行
    /*
        1.执行若干代码
    */
    next();//2.执行next() 匹配其他路由
    
    //4.再执行
    if(ctx.status==404){
        ctx.status=404
        ctx.body="这是一个404"
    }else{
        console.log(ctx.url)
    }
})
//3.匹配下面的路由
 router.get('/news',async(ctx)=>{
     console.log("this is news")
     ctx.body="这是一个新闻页面"
 })第三方中间件
//安装
npm install koa-static --save
//使用
//引入
const static=require('koa-static')
//使用
app.use(static('static')) //去static文件目录中将中找文件,如果能找到对应的文件,找不到就next()
app.use(static(__dirname+'/static'))
app.use(static(__dirname+'/public'))
中间件执行顺序
Golang-Gin
定义中间件
package main
import(
  "github.com/gin-gonic/gin"
)
func main(){
    r:=gin.Default()
    r.GET("/index",func(c *gin.Context){
        //...
    })
    r.Run()
}
func m1(c *gin.Context){
    fmt.Println("中间件m1")
    
    c.Next()//调用后续的处理函数
    //c.Abort()//阻止调用后续的处理函数
    
    fmt.Println("m1 out...")
}
注册中间件
全局注册-某个路由单独注册-路由组注册
package main
import(
    "github.com/gin-gonic/gin"
)
func main(){
    r:=gin.Default()
    r.GET("/index",func(c *gin.Context){
        //...
    })
    
    //某个路由单独注册--也可以取名为路由级注册中间件
    r.GET("/test1",m1,func(c *gin.Context){
        //...
    })
    
    //路由组注册
    xxGroup:=r.Group("/xx",m1)
    {
        xxGroup.GET("/index",func(c *gin.Context){
            //...
        }) 
    }
    
    xx2Group:=r.Group("/xx2")
    xx2Group.Use(m1)
    {
        xxGroup.GET("/index",func(c *gin.Context){
            //...
        }) 
    }
    r.Run()
     r.GET("/index",m1)
}
func m1(c *gin.Context){
    fmt.Println("中间件m1")
    
    c.Next()//调用后续的处理函数
    //c.Abort()//阻止调用后续的处理函数
    //return 连下方的fmt.Println都不执行了,立即返回
    fmt.Println("m1 out...")
}
r.Use(m1)//全局注册
//多个中间件注册
r.Use(m1,m2)中间件执行顺序
中间件通常写法-闭包
func authMiddleware(doCheck bool) gin.HandlerFunc{
    //连接数据库
    //或准备工作
    return func(c *gin.Context){
        //是否登录判断
        //if是登录用户
        //c.Next()
        //else
        //c.Abort()
    }
}中间件通信
func m1(c *gin.Context){
    fmt.Println("m1 in ...")
    
    start := time.Now()
    c.Next()
    cost:=time.Since(start)
    fmt.Printf("cost:%v\n",cost)
    fmt.Println("m1 out...")
}
func m2(c *gin.Context){
    fmt.Println("m2 in...")
    //中间件存值
    c.Set("name","carfield")
    fmt.Println("m2 out...")
    //其他中间件取值
    // c.Get
    // c.MustGet
}
中间件中使用goroutine
(c *gin.Context) 必须使用其只读副本c.Copy(),否则会出现线程安全问题。.Net Core-Asp.net core
创建中间件管道
//Run
public class Startup
{
 public void Configure(IApplicationBuilder app)
 {
     app.Run(async context =>
     {
         await context.Response.WriteAsync("Hello, World!");
     });
 }
}
//Use - Run
public class Startup
{
 public void Configure(IApplicationBuilder app)
 {
     app.Use(async (context, next) =>
     {
         // Do work that doesn't write to the Response.
         await next.Invoke();
         // Do logging or other work that doesn't write to the Response.
     });
     app.Run(async context =>
     {
         await context.Response.WriteAsync("Hello from 2nd delegate.");
     });
 }
}
//这个Use是不是跟koa的应用级中间件很像创建中间件管道分支
Map 基于给定请求路径的匹配项来创建请求管道分支。 如果请求路径以给定路径开头,则执行分支。koa和gin中路由匹配就是map这种,当不使用内置的mvc模板路由,我姑且称它为自定义路由public class Startup
{
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }
    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }
    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);
        app.Map("/map2", HandleMapTest2);
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate. 内置中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        //开发人员异常页中间件 报告应用运行时错误
        app.UseDeveloperExceptionPage();
        
        //数据库错误页中间件报告数据库运行时错误
        app.UseDatabaseErrorPage();
    }
    else
    {
        //异常处理程序中间件
        app.UseExceptionHandler("/Error");
        //http严格传输安全协议中间件
        app.UseHsts();
    }
    //HTTPS重定向中间件
    app.UseHttpsRedirection();
    
    //静态文件中间件
    app.UseStaticFiles();
    
    //Cookie策略中间件
    app.UseCookiePolicy();
    
    //路由中间件
    app.UseRouting();
    
    //身份验证中间件
    app.UseAuthentication();
    
    //授权中间件
    app.UseAuthorization();
    
    //会话中间件-如果使用session,就需要把cookie策略中间件先使用了,再引入session中间件,再引入mvc中间件,毕竟session是依赖cookie实现的
    app.UseSession();
    
    //终结点路由中间件
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}自定义中间件
在
Configure中直接写//在Startup.Configure直接编码
public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            //做一些操作
            // Call the next delegate/middleware in the pipeline
            await next();
        });
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync(
                $"Hello world");
        });
    }中间件类+中间件扩展方法+UseXX
Startup.Configure直接编码,当定义多个中间件,代码难免变得臃肿,不利于维护,看看内置的中间件,app.UseAuthentication();多简洁,查看asp.net core源码,内置的中间件都是一个中间件类xxMiddleware.cs 一个扩展方法 xxMiddlewareExtensions.cs 然后在Startup.Configure 中使用扩展方法调用Usexx()using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;
namespace Culture
{
    public class RequestTestMiddleware
    {
        private readonly RequestDelegate _next;
        //具有类型为 RequestDelegate 的参数的公共构造函数
        public RequestTestMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        //名为 Invoke 或 InvokeAsync 的公共方法。 此方法必须:
        //返回 Task。
        //接受类型 HttpContext 的第一个参数。
        public async Task InvokeAsync(HttpContext context)
        {
            //做一些操作
            // Call the next delegate/middleware in the pipeline
            await _next(context);
        }
    }
}
//中间件扩展方法
using Microsoft.AspNetCore.Builder;
namespace Culture
{
    public static class RequestTestMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestTest(
            this IApplicationBuilder app)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }
            return app.UseMiddleware.Net -Asp.Net
文章标题:【对比学习】koa.js、Gin与asp.net core——中间件
文章链接:http://soscw.com/essay/77201.html