1. 程式人生 > >【ASP.NET Core】如何隱藏響應頭中的 “Kestrel”

【ASP.NET Core】如何隱藏響應頭中的 “Kestrel”

cat 執行 content 裝逼 調用 iap filter col 很好

全宇宙人民都知道,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 修改。

技術分享圖片

效果一樣。

好了,今天就扯到這裏,不算什麽高大上技巧。

【ASP.NET Core】如何隱藏響應頭中的 “Kestrel”