zoukankan      html  css  js  c++  java
  • 【ASP.NET Core】如何隐藏响应头中的 “Kestrel”

    全宇宙人民都知道,ASP.NET Core 应用是不依赖服务器组件的,因此它可以独立运行,一般是使用支持跨平台的 Kestrel 服务器(当然,在 Windows 上还可以考虑用 HttpSys,但要以管理员身份运行)。

    尽管 SDK 文档中推荐我们用服务器组件来“反向”代理,但独立运行也是允许的。当 Web 应用独立运行的时候,客户端发出请求后,在响应的 HTTP 消息中,会附上一个 Server 头,其值就是 Kestrel。如下面的高清无码无水印截图所示。

    看到了吧,Server = Kestrel。上面老周做了个小站,并且是独立运行的,但我想隐藏那个 Kestrel 名字,想把它改为 Pig Platform。既然想到了,那就动手,这个其实很好办的,只要在中间件的 HTTP 管道中插入一个自定义的中间件,修改一下 Server 头就行了。

    实现方法就是在 Startup 类的 Configure 方法中 Use 一下就好了。

            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.Use(async (context, next) =>
                {
                    context.Response.Headers["Server"] = "Bun Server 2098";
                    await next();
                });
                app.UseMvc();
            }

    因为代码不多,就没必要写中间件类了,直接 Use 方法传委托就OK了。代码固然是全宇宙最简单的,可是,你得注意顺序,啥意思呢,比如我改为这样。

                app.Use(async (context, next) =>
                {
                    await next();
                    context.Response.Headers["Server"] = "Bun Server 2098";
                });

    这样修改后会出错,因为 next 直接进入下一个中间件,而这“下一个”中间件就可能是 MVC 了,这时候 HTTP 头的集合被锁定,变成只读了,一修改就出错。所以,要在进入下一个中间件之前把 Server 头改掉。

    故,这样才不会出错。

                    context.Response.Headers["Server"] = "Bun Server 2098";
                    await next();

    如此处理后,当客户端访问时,Server 头就变成这样。

     效果是做到了,可,这样一来,咱们的 Startup.Configure 方法好像不够简洁。而且,这代码太不够逼格,严重不符合现在年轻人热衷于装逼的时代需求。

    为了让其适应一切以装逼为核心的时代精神,我们可以使用 Starup Filter。

    看名字你会猜到,是个过滤器,它的作用就是:能把中间件插入到 HTTP 消息管道的最前面,或者最后面。实现 Filter 的方法是实现 IStartupFilter 接口。这个接口只有一个方法。

      Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);

    这个方法和 Startup 类中的 Configure 方法很像。参数和返回值都一个带 IApplicationBuilder 参数的委托。方法的 next 参数是下一个要执行的 Configure 方法,可能是下一个 Startup Filter 的 Configure 方法,也可能是 Startup 类的 Configure 方法。返回值就是我们对当前的 Configure 方法的处理。

    先看看我的实现。

        public class MyStartupFilter : IStartupFilter
        {
            public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
            {
                return app =>
                {
                    app.Use(async (context, _next) =>
                    {
                        context.Response.Headers.Add("Server", "Big Server");
                        await _next();
                    });
                    next(app);
                };
            }
        }

    在这个项目中,除了运行库内部的,外部实现的 Starup Filter 只有一个—— MyStartupFilter ,所以,在 Configure 方法中,参数 next 就是 Startup 类的 Configure 方法。因此,在这里,你可以决定应用程序是否执行 Startup 类中的 Configure 方法。

    上面代码的意思就是:先为应用程序注册我们自己的中间件(此处是委托),修改 Server HTTP 头,然后再调用 Startup 类中 Configure 方法。如此就使得我们自定义的中间件代码被入到整个 HTTP 消息管道的前面。

    这时候,你可以把 Startup 类中刚刚写的代码删掉了,使用 Configure 方法继续保持简洁。

            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                //app.Use(async (context, next) =>
                //{
                //    context.Response.Headers["Server"] = "Bun Server 2098";
                //    await next();
                //});
                app.UseMvc();
            }

    那么这个 Startup Filter 类怎么用呢,好像没有添加的相关 API 。其实,ASP.NET Core 有一个万能法则——依赖注入。当你自己写的任何扩展类型不知道怎么使用时,你就统统放进 ServiceCollection 里面就好了。于是,可以修改 Starup 类的 ConfigureServices 方法。

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc().WithRazorPagesAtContentRoot().AddRazorPagesOptions(o=>
                {
                    o.Conventions.AddPageRoute("/Main", "");
                });
               services.AddTransient<IStartupFilter, MyStartupFilter>();
            }

    ServiceCollection 有三种 Add 方法,用途一样,不同的是对象实例的生命周期。

    1、AddSingleton:活得最长,寿与天齐。整个应用程序中它只产生一个实例。

    2、AddScoped:寿命稍短,它主要在同一次 HTTP 请求中有效,从收到 HTTP 请求时创建实例,请求结束后销毁实例。

    3、AddTransient:这个最短命,用的时候创建实例,用完就扔。

    我们这个 Startup Filter 只在应用初始化时用一次,后续不再使用,所以用 AddTransient 方法添加就行了,整个应用中就用一次,没必要占着位置不放。

    此时,访问服务器,也能将默认的 Kestrel 修改。

    效果一样。

    好了,今天就扯到这里,不算什么高大上技巧。

  • 相关阅读:
    [django]django models最佳实战
    [vue]模拟移动端三级路由: router-link位置体现router的灵活性
    [js]顶部导航和内容区布局
    [django]django查询最佳实战
    [vue]webpack使用样式
    [vue]webpack中使用组件
    [vue]组件的导入
    [django]django权限简单实验
    [django]前后端分离之JWT用户认证
    [django]drf知识点梳理-权限
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/8665278.html
Copyright © 2011-2022 走看看